@drmhse/authos-vue 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,462 +3,68 @@
3
3
  [![npm version](https://img.shields.io/npm/v/@drmhse/authos-vue)](https://www.npmjs.com/package/@drmhse/authos-vue)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
5
5
 
6
- Vue 3 adapter for [AuthOS](https://authos.dev) - the multi-tenant authentication platform. Provides Vue composables, components, and Nuxt module.
6
+ Vue 3 and Nuxt adapter for AuthOS.
7
7
 
8
- ## Quick Start (5 minutes)
8
+ Full documentation: [authos.dev/docs/packages/authos-vue/](https://authos.dev/docs/packages/authos-vue/)
9
+
10
+ AI agent skills: [authos.dev/docs/ai-agent-skills/](https://authos.dev/docs/ai-agent-skills/) and [github.com/CkCreative/authos_skill](https://github.com/CkCreative/authos_skill)
11
+
12
+ ## Install
9
13
 
10
14
  ```bash
11
15
  npm install @drmhse/authos-vue
12
16
  ```
13
17
 
14
- Install the plugin and you're ready to go:
18
+ ## Quick start
15
19
 
16
20
  ```ts
17
- // main.ts
18
21
  import { createApp } from 'vue';
19
22
  import { createAuthOS } from '@drmhse/authos-vue';
20
23
  import App from './App.vue';
21
24
 
22
25
  const app = createApp(App);
23
26
 
24
- app.use(createAuthOS({
25
- baseURL: 'https://sso.example.com',
26
- }));
27
+ app.use(
28
+ createAuthOS({
29
+ baseURL: 'https://sso.example.com',
30
+ }),
31
+ );
27
32
 
28
33
  app.mount('#app');
29
34
  ```
30
35
 
31
36
  ```vue
32
- <!-- App.vue -->
33
37
  <script setup>
34
38
  import { SignIn, SignedIn, SignedOut, UserButton } from '@drmhse/authos-vue';
35
39
  </script>
36
40
 
37
41
  <template>
38
42
  <SignedOut>
39
- <SignIn @success="console.log('Welcome!')" />
43
+ <SignIn />
40
44
  </SignedOut>
41
45
  <SignedIn>
42
46
  <UserButton />
43
- <p>You're signed in!</p>
44
47
  </SignedIn>
45
48
  </template>
46
49
  ```
47
50
 
48
- That's it. You now have:
49
- - Email/password authentication with MFA support
50
- - Automatic session management
51
- - User dropdown with logout
52
- - Conditional rendering based on auth state
53
-
54
- ## Usage Modes
55
-
56
- AuthOS supports two usage modes:
57
-
58
- ### Platform-Level Access
59
-
60
- For platform owners and administrators, use without `org`/`service`:
61
-
62
- ```ts
63
- app.use(createAuthOS({
64
- baseURL: 'https://sso.example.com',
65
- }));
66
- ```
67
-
68
- ### Multi-Tenant Access (Organizations)
69
-
70
- For tenant applications with OAuth support, add `org` and `service`:
71
-
72
- ```ts
73
- app.use(createAuthOS({
74
- baseURL: 'https://sso.example.com',
75
- org: 'acme-corp', // Organization slug
76
- service: 'main-app', // Service slug
77
- }));
78
- ```
79
-
80
- ### Using an Existing Client
81
-
82
- For advanced use cases, you can pass a pre-configured `SsoClient`:
83
-
84
- ```ts
85
- import { SsoClient } from '@drmhse/sso-sdk';
86
- import { createAuthOS } from '@drmhse/authos-vue';
87
-
88
- // Create client with custom configuration
89
- const client = new SsoClient({
90
- baseURL: 'https://sso.example.com',
91
- storage: customStorage,
92
- });
93
-
94
- app.use(createAuthOS({ client }));
95
- ```
96
-
97
- ## OAuth / Social Login
98
-
99
- To use OAuth providers (GitHub, Google, Microsoft), configure your organization and service (see Multi-Tenant Access above):
51
+ ## Scoped tenant usage
100
52
 
101
53
  ```ts
102
- app.use(createAuthOS({
103
- baseURL: 'https://sso.example.com',
104
- org: 'my-org', // Your organization slug
105
- service: 'my-app', // Your service slug
106
- redirectUri: 'https://app.example.com/callback', // Optional
107
- }));
108
- ```
109
-
110
- Then use individual OAuth buttons:
111
-
112
- ```vue
113
- <script setup>
114
- import { OAuthButton } from '@drmhse/authos-vue';
115
- </script>
116
-
117
- <template>
118
- <OAuthButton provider="github" />
119
- <OAuthButton provider="google">Sign in with Google</OAuthButton>
120
- <OAuthButton provider="microsoft" />
121
- </template>
122
- ```
123
-
124
- ## Components
125
-
126
- ### SignIn
127
-
128
- Complete sign-in form with email/password authentication. Supports scoped slots for custom UI.
129
-
130
- ```vue
131
- <script setup>
132
- import { SignIn } from '@drmhse/authos-vue';
133
-
134
- function handleSuccess() {
135
- router.push('/dashboard');
136
- }
137
- </script>
138
-
139
- <template>
140
- <SignIn @success="handleSuccess" @error="console.error" />
141
- </template>
142
- ```
143
-
144
- **Events:**
145
- | Event | Payload | Description |
146
- |-------|---------|-------------|
147
- | `@success` | - | Fired after successful login |
148
- | `@error` | `Error` | Fired on login error |
149
-
150
- **Scoped Slot:**
151
- ```vue
152
- <SignIn v-slot="{ email, password, step, error, isSubmitting, updateEmail, updatePassword, submit }">
153
- <form @submit.prevent="submit">
154
- <input :value="email" @input="e => updateEmail(e.target.value)" />
155
- <input :value="password" type="password" @input="e => updatePassword(e.target.value)" />
156
- <button :disabled="isSubmitting">Sign In</button>
157
- <p v-if="error">{{ error }}</p>
158
- </form>
159
- </SignIn>
160
- ```
161
-
162
- ### SignUp
163
-
164
- Registration form for new users.
165
-
166
- ```vue
167
- <SignUp @success="console.log('Check your email!')" @error="console.error" />
168
- ```
169
-
170
- ### MagicLinkSignIn
171
-
172
- Sign-in component for Magic Links (passwordless).
173
-
174
- ```vue
175
- <MagicLinkSignIn @success="console.log('Magic link sent!')" />
176
- ```
177
-
178
- ### PasskeySignIn
179
-
180
- Sign-in component for Passkeys (WebAuthn).
181
-
182
- ```vue
183
- <PasskeySignIn @success="console.log('Authenticated!')" />
184
- ```
185
-
186
- ### SignedIn / SignedOut
187
-
188
- Conditional rendering based on authentication state. Inspired by Clerk's API.
189
-
190
- ```vue
191
- <SignedIn>
192
- <!-- Only shown when user is logged in -->
193
- <UserButton />
194
- </SignedIn>
195
-
196
- <SignedOut>
197
- <!-- Only shown when user is logged out -->
198
- <SignIn />
199
- </SignedOut>
200
- ```
201
-
202
- ### UserButton
203
-
204
- User menu button with avatar and logout.
205
-
206
- ```vue
207
- <UserButton @logout="router.push('/')" />
208
- ```
209
-
210
- ### OrganizationSwitcher
211
-
212
- Dropdown to switch between organizations.
213
-
214
- When switching organizations, the SDK automatically issues new JWT tokens with the new organization context, enabling seamless multi-tenant switching without re-authentication.
215
-
216
- ```vue
217
- <OrganizationSwitcher @switch="org => console.log('Switched to:', org.name)" />
218
- ```
219
-
220
- ### Protect
221
-
222
- Conditional rendering based on user permissions.
223
-
224
- ```vue
225
- <Protect permission="admin:access">
226
- <template #default>
227
- <AdminDashboard />
228
- </template>
229
- <template #fallback>
230
- <p>Access denied</p>
231
- </template>
232
- </Protect>
233
- ```
234
-
235
- ### OAuthButton
236
-
237
- Individual OAuth provider button. Requires `org` and `service` in plugin options.
238
-
239
- ```vue
240
- <OAuthButton provider="github" />
241
- <OAuthButton provider="google">Continue with Google</OAuthButton>
242
- ```
243
-
244
- **Scoped Slot:**
245
- ```vue
246
- <OAuthButton provider="github" v-slot="{ providerName, isConfigured, handleClick }">
247
- <button @click="handleClick" :disabled="!isConfigured">
248
- Continue with {{ providerName }}
249
- </button>
250
- </OAuthButton>
251
- ```
252
-
253
- ## Composables
254
-
255
- ### useAuthOS
256
-
257
- Access the AuthOS client, state, and configuration.
258
-
259
- ```vue
260
- <script setup>
261
- import { useAuthOS } from '@drmhse/authos-vue';
262
-
263
- const { client, options, isAuthenticated, isLoading } = useAuthOS();
264
-
265
- async function handleLogout() {
266
- await client.auth.logout();
267
- }
268
- </script>
269
- ```
270
-
271
- ### useUser
272
-
273
- Get the current user's profile.
274
-
275
- ```vue
276
- <script setup>
277
- import { useUser } from '@drmhse/authos-vue';
278
-
279
- const { user, isLoading } = useUser();
280
- </script>
281
-
282
- <template>
283
- <div v-if="isLoading">Loading...</div>
284
- <div v-else>Welcome, {{ user?.email }}</div>
285
- </template>
286
- ```
287
-
288
- ### useOrganization
289
-
290
- Get and switch between organizations.
291
-
292
- ```vue
293
- <script setup>
294
- import { useOrganization } from '@drmhse/authos-vue';
295
-
296
- const { currentOrganization, organizations, switchOrganization, isSwitching } = useOrganization();
297
- </script>
298
-
299
- <template>
300
- <h3>{{ currentOrganization?.name }}</h3>
301
- <ul>
302
- <li v-for="org in organizations" :key="org.id">
303
- <button @click="switchOrganization(org.slug)">{{ org.name }}</button>
304
- </li>
305
- </ul>
306
- </template>
307
- ```
308
-
309
- ### usePermission / useAnyPermission / useAllPermissions
310
-
311
- Check user permissions.
312
-
313
- ```vue
314
- <script setup>
315
- import { usePermission, useAnyPermission, useAllPermissions } from '@drmhse/authos-vue';
316
-
317
- const canAccessAdmin = usePermission('admin:access');
318
- const canReadOrWrite = useAnyPermission(['read:data', 'write:data']);
319
- const hasFullAccess = useAllPermissions(['read:data', 'write:data', 'delete:data']);
320
- </script>
321
-
322
- <template>
323
- <button v-if="canAccessAdmin">Admin Panel</button>
324
- </template>
325
- ```
326
-
327
- ## Nuxt Integration
328
-
329
- ### Plugin Installation
330
-
331
- ```ts
332
- // nuxt.config.ts
333
- export default defineNuxtConfig({
334
- modules: ['@drmhse/authos-vue/nuxt'],
335
- });
336
- ```
337
-
338
- ### Auth Middleware
339
-
340
- ```ts
341
- // middleware/auth.ts
342
- import { authMiddleware } from '@drmhse/authos-vue/nuxt';
343
-
344
- export default authMiddleware({
345
- redirectTo: '/login',
346
- });
347
- ```
348
-
349
- Then use in your pages:
350
-
351
- ```vue
352
- <script setup>
353
- definePageMeta({
354
- middleware: ['auth'],
355
- });
356
- </script>
357
-
358
- <template>
359
- <div>Protected page</div>
360
- </template>
361
- ```
362
-
363
- ### Server-Side Usage
364
-
365
- ```ts
366
- // server/api/user.get.ts
367
- import { currentUser } from '@drmhse/authos-vue/nuxt';
368
-
369
- export default defineEventHandler(async (event) => {
370
- const user = await currentUser(event);
371
-
372
- if (!user) {
373
- throw createError({
374
- statusCode: 401,
375
- message: 'Unauthorized',
376
- });
377
- }
378
-
379
- return user;
380
- });
381
- ```
382
-
383
- ## Configuration Reference
384
-
385
- ### createAuthOS Options
386
-
387
- | Option | Type | Required | Description |
388
- |--------|------|----------|-------------|
389
- | `baseURL` | `string` | ✅ | AuthOS API URL |
390
- | `org` | `string` | For OAuth | Organization slug for OAuth flows |
391
- | `service` | `string` | For OAuth | Service slug for OAuth flows |
392
- | `redirectUri` | `string` | - | OAuth redirect URI (defaults to origin + '/callback') |
393
- | `afterSignInUrl` | `string` | - | Redirect URL after sign-in |
394
- | `afterSignUpUrl` | `string` | - | Redirect URL after sign-up |
395
- | `storage` | `TokenStorage` | - | Custom token storage |
396
- | `autoRefresh` | `boolean` | - | Auto-refresh expired tokens (default: true) |
397
- | `initialToken` | `string` | - | SSR token for hydration |
398
-
399
- ## Styling
400
-
401
- AuthOS components come with **polished default styling** out of the box, similar to best-in-class auth providers. The styling is fully customizable via the `appearance` option or by overriding CSS variables.
402
-
403
- ### Customization
404
-
405
- You can customize the theme colors, fonts, and more by passing an `appearance` object to `createAuthOS`.
406
-
407
- ```ts
408
- app.use(createAuthOS({
409
- // ... other options
410
- appearance: {
411
- variables: {
412
- colorPrimary: '#0066cc',
413
- colorBackground: '#f5f5f5',
414
- borderRadius: '0.25rem',
415
- fontFamily: 'Inter, sans-serif',
416
- },
417
- },
418
- }));
419
- ```
420
-
421
- ### CSS Variables
422
-
423
- You can also override these CSS variables in your own stylesheet:
424
-
425
- ```css
426
- :root {
427
- --authos-color-primary: #0066cc;
428
- --authos-border-radius: 4px;
429
- }
430
- ```
431
-
432
- ### Headless Styling
433
-
434
- If you prefer to completely style the components yourself, you can target the data attributes. The default styles have low specificity, so your CSS classes will easily override them.
435
-
436
- ```css
437
- [data-authos-signin] { /* Container */ }
438
- [data-authos-field="email"] { /* Email field wrapper */ }
439
- [data-authos-field="password"] { /* Password field wrapper */ }
440
- [data-authos-submit] { /* Submit button */ }
441
- [data-authos-error] { /* Error message */ }
442
- [data-authos-oauth] { /* OAuth button */ }
443
- [data-authos-oauth][data-provider="github"] { /* GitHub button */ }
444
- [data-authos-divider] { /* "or" divider */ }
445
- [data-authos-magic-link] { /* Magic Link container */ }
446
- [data-authos-passkey] { /* Passkey container */ }
447
- ```
448
-
449
- ## Migration from v1
450
-
451
- If you're upgrading from v1, note the following breaking change:
452
-
453
- ```diff
454
- app.use(createAuthOS({
455
- - baseUrl: 'https://sso.example.com',
456
- + baseURL: 'https://sso.example.com',
457
- }));
54
+ app.use(
55
+ createAuthOS({
56
+ baseURL: 'https://sso.example.com',
57
+ org: 'acme-corp',
58
+ service: 'main-app',
59
+ redirectUri: 'https://app.acme.com/callback',
60
+ }),
61
+ );
458
62
  ```
459
63
 
460
- The `baseUrl` property has been renamed to `baseURL` (uppercase URL) for consistency with the React package and underlying SDK.
64
+ ## Includes
461
65
 
462
- ## License
66
+ - Plugin factory `createAuthOS`
67
+ - Components such as `SignIn`, `SignUp`, `Callback`, `OAuthButton`, `Protect`, and `OrganizationSwitcher`
68
+ - Composables for auth state, profile data, organizations, and permissions
463
69
 
464
- MIT © DRM HSE
70
+ See the docs site for Nuxt details, slot APIs, and advanced integration patterns.
@@ -0,0 +1,68 @@
1
+ // ../../node_modules/confbox/dist/_chunks/libs/detect-indent.mjs
2
+ var e = /^(?:( )+|\t+)/;
3
+ var t = `space`;
4
+ function n(e2, n3, r3) {
5
+ return e2 && n3 === t && r3 === 1;
6
+ }
7
+ function r(r3, a3) {
8
+ let o3 = /* @__PURE__ */ new Map(), s2 = 0, c2, l;
9
+ for (let u of r3.split(/\n/g)) {
10
+ if (!u) continue;
11
+ let r4 = u.match(e);
12
+ if (r4 === null) s2 = 0, c2 = ``;
13
+ else {
14
+ let e2 = r4[0].length, u2 = r4[1] ? t : `tab`;
15
+ if (n(a3, u2, e2)) continue;
16
+ u2 !== c2 && (s2 = 0), c2 = u2;
17
+ let d = 1, f = 0, p = e2 - s2;
18
+ if (s2 = e2, p === 0) d = 0, f = 1;
19
+ else {
20
+ let e3 = Math.abs(p);
21
+ if (n(a3, u2, e3)) continue;
22
+ l = i(u2, e3);
23
+ }
24
+ let m = o3.get(l);
25
+ o3.set(l, m === void 0 ? [1, 0] : [m[0] + d, m[1] + f]);
26
+ }
27
+ }
28
+ return o3;
29
+ }
30
+ function i(e2, n3) {
31
+ return (e2 === t ? `s` : `t`) + String(n3);
32
+ }
33
+ function a(e2) {
34
+ return { type: e2[0] === `s` ? t : `tab`, amount: Number(e2.slice(1)) };
35
+ }
36
+ function o(e2) {
37
+ let t3, n3 = 0, r3 = 0;
38
+ for (let [i3, [a3, o3]] of e2) (a3 > n3 || a3 === n3 && o3 > r3) && (n3 = a3, r3 = o3, t3 = i3);
39
+ return t3;
40
+ }
41
+ function s(e2, n3) {
42
+ return (e2 === t ? ` ` : ` `).repeat(n3);
43
+ }
44
+ function c(e2) {
45
+ if (typeof e2 != `string`) throw TypeError(`Expected a string`);
46
+ let t3 = r(e2, true);
47
+ t3.size === 0 && (t3 = r(e2, false));
48
+ let n3 = o(t3), i3, c2 = 0, l = ``;
49
+ return n3 !== void 0 && ({ type: i3, amount: c2 } = a(n3), l = s(i3, c2)), { amount: c2, type: i3, indent: l };
50
+ }
51
+
52
+ // ../../node_modules/confbox/dist/_chunks/_format.mjs
53
+ var t2 = /* @__PURE__ */ Symbol.for(`__confbox_fmt__`);
54
+ var n2 = /^(\s+)/;
55
+ var r2 = /(\s+)$/;
56
+ function i2(e2, t3 = {}) {
57
+ return { sample: t3.indent === void 0 && t3.preserveIndentation !== false && e2.slice(0, t3?.sampleSize || 1024), whiteSpace: t3.preserveWhitespace === false ? void 0 : { start: n2.exec(e2)?.[0] || ``, end: r2.exec(e2)?.[0] || `` } };
58
+ }
59
+ function a2(e2, n3, r3) {
60
+ !n3 || typeof n3 != `object` || Object.defineProperty(n3, t2, { enumerable: false, configurable: true, writable: true, value: i2(e2, r3) });
61
+ }
62
+ function o2(n3, r3) {
63
+ if (!n3 || typeof n3 != `object` || !(t2 in n3)) return { indent: r3?.indent ?? 2, whitespace: { start: ``, end: `` } };
64
+ let i3 = n3[t2];
65
+ return { indent: r3?.indent || c(i3.sample || ``).indent, whitespace: i3.whiteSpace || { start: ``, end: `` } };
66
+ }
67
+
68
+ export { a2 as a, o2 as o };