@drmhse/authos-vue 0.2.4 → 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,493 +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`:
51
+ ## Scoped tenant usage
61
52
 
62
53
  ```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):
100
-
101
- ```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
- ### Callback
254
-
255
- Required for OAuth flows. Handles the redirect from the identity provider by parsing tokens from the URL fragment and setting the session.
256
-
257
- ```vue
258
- <script setup>
259
- import { Callback } from '@drmhse/authos-vue';
260
- import { useRouter } from 'vue-router';
261
-
262
- const router = useRouter();
263
-
264
- function handleSuccess() {
265
- router.push('/');
266
- }
267
-
268
- function handleError(error) {
269
- console.error('Login failed:', error);
270
- }
271
- </script>
272
-
273
- <template>
274
- <Callback @success="handleSuccess" @error="handleError" />
275
- </template>
276
- ```
277
-
278
- **Events:**
279
- | Event | Payload | Description |
280
- |-------|---------|-------------|
281
- | `@success` | - | Fired after session is successfully set |
282
- | `@error` | `Error` | Fired on error |
283
-
284
- ## Composables
285
-
286
- ### useAuthOS
287
-
288
- Access the AuthOS client, state, and configuration.
289
-
290
- ```vue
291
- <script setup>
292
- import { useAuthOS } from '@drmhse/authos-vue';
293
-
294
- const { client, options, isAuthenticated, isLoading } = useAuthOS();
295
-
296
- async function handleLogout() {
297
- await client.auth.logout();
298
- }
299
- </script>
300
- ```
301
-
302
- ### useUser
303
-
304
- Get the current user's profile.
305
-
306
- ```vue
307
- <script setup>
308
- import { useUser } from '@drmhse/authos-vue';
309
-
310
- const { user, isLoading } = useUser();
311
- </script>
312
-
313
- <template>
314
- <div v-if="isLoading">Loading...</div>
315
- <div v-else>Welcome, {{ user?.email }}</div>
316
- </template>
317
- ```
318
-
319
- ### useOrganization
320
-
321
- Get and switch between organizations.
322
-
323
- ```vue
324
- <script setup>
325
- import { useOrganization } from '@drmhse/authos-vue';
326
-
327
- const { currentOrganization, organizations, switchOrganization, isSwitching } = useOrganization();
328
- </script>
329
-
330
- <template>
331
- <h3>{{ currentOrganization?.name }}</h3>
332
- <ul>
333
- <li v-for="org in organizations" :key="org.id">
334
- <button @click="switchOrganization(org.slug)">{{ org.name }}</button>
335
- </li>
336
- </ul>
337
- </template>
338
- ```
339
-
340
- ### usePermission / useAnyPermission / useAllPermissions
341
-
342
- Check user permissions.
343
-
344
- ```vue
345
- <script setup>
346
- import { usePermission, useAnyPermission, useAllPermissions } from '@drmhse/authos-vue';
347
-
348
- const canAccessAdmin = usePermission('admin:access');
349
- const canReadOrWrite = useAnyPermission(['read:data', 'write:data']);
350
- const hasFullAccess = useAllPermissions(['read:data', 'write:data', 'delete:data']);
351
- </script>
352
-
353
- <template>
354
- <button v-if="canAccessAdmin">Admin Panel</button>
355
- </template>
356
- ```
357
-
358
- ## Nuxt Integration
359
-
360
- ### Plugin Installation
361
-
362
- ```ts
363
- // nuxt.config.ts
364
- export default defineNuxtConfig({
365
- modules: ['@drmhse/authos-vue/nuxt'],
366
- });
367
- ```
368
-
369
- ### Auth Middleware
370
-
371
- ```ts
372
- // middleware/auth.ts
373
- import { authMiddleware } from '@drmhse/authos-vue/nuxt';
374
-
375
- export default authMiddleware({
376
- redirectTo: '/login',
377
- });
378
- ```
379
-
380
- Then use in your pages:
381
-
382
- ```vue
383
- <script setup>
384
- definePageMeta({
385
- middleware: ['auth'],
386
- });
387
- </script>
388
-
389
- <template>
390
- <div>Protected page</div>
391
- </template>
392
- ```
393
-
394
- ### Server-Side Usage
395
-
396
- ```ts
397
- // server/api/user.get.ts
398
- import { currentUser } from '@drmhse/authos-vue/nuxt';
399
-
400
- export default defineEventHandler(async (event) => {
401
- const user = await currentUser(event);
402
-
403
- if (!user) {
404
- throw createError({
405
- statusCode: 401,
406
- message: 'Unauthorized',
407
- });
408
- }
409
-
410
- return user;
411
- });
412
- ```
413
-
414
- ## Configuration Reference
415
-
416
- ### createAuthOS Options
417
-
418
- | Option | Type | Required | Description |
419
- |--------|------|----------|-------------|
420
- | `baseURL` | `string` | ✅ | AuthOS API URL |
421
- | `org` | `string` | For OAuth | Organization slug for OAuth flows |
422
- | `service` | `string` | For OAuth | Service slug for OAuth flows |
423
- | `redirectUri` | `string` | - | OAuth redirect URI (defaults to origin + '/callback') |
424
- | `afterSignInUrl` | `string` | - | Redirect URL after sign-in |
425
- | `afterSignUpUrl` | `string` | - | Redirect URL after sign-up |
426
- | `storage` | `TokenStorage` | - | Custom token storage |
427
- | `autoRefresh` | `boolean` | - | Auto-refresh expired tokens (default: true) |
428
- | `initialToken` | `string` | - | SSR token for hydration |
429
-
430
- ## Styling
431
-
432
- 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.
433
-
434
- ### Customization
435
-
436
- You can customize the theme colors, fonts, and more by passing an `appearance` object to `createAuthOS`.
437
-
438
- ```ts
439
- app.use(createAuthOS({
440
- // ... other options
441
- appearance: {
442
- variables: {
443
- colorPrimary: '#0066cc',
444
- colorBackground: '#f5f5f5',
445
- borderRadius: '0.25rem',
446
- fontFamily: 'Inter, sans-serif',
447
- },
448
- },
449
- }));
450
- ```
451
-
452
- ### CSS Variables
453
-
454
- You can also override these CSS variables in your own stylesheet:
455
-
456
- ```css
457
- :root {
458
- --authos-color-primary: #0066cc;
459
- --authos-border-radius: 4px;
460
- }
461
- ```
462
-
463
- ### Headless Styling
464
-
465
- 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.
466
-
467
- ```css
468
- [data-authos-signin] { /* Container */ }
469
- [data-authos-field="email"] { /* Email field wrapper */ }
470
- [data-authos-field="password"] { /* Password field wrapper */ }
471
- [data-authos-submit] { /* Submit button */ }
472
- [data-authos-error] { /* Error message */ }
473
- [data-authos-oauth] { /* OAuth button */ }
474
- [data-authos-oauth][data-provider="github"] { /* GitHub button */ }
475
- [data-authos-divider] { /* "or" divider */ }
476
- [data-authos-magic-link] { /* Magic Link container */ }
477
- [data-authos-passkey] { /* Passkey container */ }
478
- ```
479
-
480
- ## Migration from v1
481
-
482
- If you're upgrading from v1, note the following breaking change:
483
-
484
- ```diff
485
- app.use(createAuthOS({
486
- - baseUrl: 'https://sso.example.com',
487
- + baseURL: 'https://sso.example.com',
488
- }));
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
+ );
489
62
  ```
490
63
 
491
- The `baseUrl` property has been renamed to `baseURL` (uppercase URL) for consistency with the React package and underlying SDK.
64
+ ## Includes
492
65
 
493
- ## 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
494
69
 
495
- 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 };