@drmhse/authos-vue 0.1.3 → 0.1.4

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
@@ -5,22 +5,13 @@
5
5
 
6
6
  Vue 3 adapter for [AuthOS](https://authos.dev) - the multi-tenant authentication platform. Provides Vue composables, components, and Nuxt module.
7
7
 
8
- ## Installation
8
+ ## Quick Start (5 minutes)
9
9
 
10
10
  ```bash
11
11
  npm install @drmhse/authos-vue
12
12
  ```
13
13
 
14
- Peer dependencies:
15
- ```bash
16
- npm install vue
17
- ```
18
-
19
- ## Quick Start
20
-
21
- ### Vue App
22
-
23
- Install the plugin and use the composables/components:
14
+ Install the plugin and you're ready to go:
24
15
 
25
16
  ```ts
26
17
  // main.ts
@@ -31,43 +22,122 @@ import App from './App.vue';
31
22
  const app = createApp(App);
32
23
 
33
24
  app.use(createAuthOS({
34
- // Required: AuthOS API URL (e.g., https://sso.example.com)
35
- baseUrl: 'https://sso.example.com'
25
+ baseURL: 'https://sso.example.com',
36
26
  }));
37
27
 
38
28
  app.mount('#app');
39
29
  ```
40
30
 
41
- ### Nuxt App
31
+ ```vue
32
+ <!-- App.vue -->
33
+ <script setup>
34
+ import { SignIn, SignedIn, SignedOut, UserButton } from '@drmhse/authos-vue';
35
+ </script>
36
+
37
+ <template>
38
+ <SignedOut>
39
+ <SignIn @success="console.log('Welcome!')" />
40
+ </SignedOut>
41
+ <SignedIn>
42
+ <UserButton />
43
+ <p>You're signed in!</p>
44
+ </SignedIn>
45
+ </template>
46
+ ```
47
+
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`:
42
61
 
43
62
  ```ts
44
- // nuxt.config.ts
45
- export default defineNuxtConfig({
46
- modules: ['@drmhse/authos-vue/nuxt']
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,
47
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>
48
122
  ```
49
123
 
50
124
  ## Components
51
125
 
52
126
  ### SignIn
53
127
 
54
- Pre-built sign-in form with email/password and OAuth provider buttons.
128
+ Complete sign-in form with email/password authentication. Supports scoped slots for custom UI.
55
129
 
56
130
  ```vue
57
- <script setup lang="ts">
131
+ <script setup>
58
132
  import { SignIn } from '@drmhse/authos-vue';
59
133
 
60
134
  function handleSuccess() {
61
- console.log('Logged in!');
62
- }
63
-
64
- function handleError(err: Error) {
65
- console.error(err);
135
+ router.push('/dashboard');
66
136
  }
67
137
  </script>
68
138
 
69
139
  <template>
70
- <SignIn @success="handleSuccess" @error="handleError" />
140
+ <SignIn @success="handleSuccess" @error="console.error" />
71
141
  </template>
72
142
  ```
73
143
 
@@ -77,52 +147,58 @@ function handleError(err: Error) {
77
147
  | `@success` | - | Fired after successful login |
78
148
  | `@error` | `Error` | Fired on login error |
79
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
+
80
162
  ### SignUp
81
163
 
82
164
  Registration form for new users.
83
165
 
84
166
  ```vue
85
- <script setup lang="ts">
86
- import { SignUp } from '@drmhse/authos-vue';
87
- </script>
88
-
89
- <template>
90
- <SignUp />
91
- </template>
167
+ <SignUp @success="console.log('Check your email!')" @error="console.error" />
92
168
  ```
93
169
 
94
- **Events:** Same as `SignIn`
170
+ ### SignedIn / SignedOut
171
+
172
+ Conditional rendering based on authentication state. Inspired by Clerk's API.
173
+
174
+ ```vue
175
+ <SignedIn>
176
+ <!-- Only shown when user is logged in -->
177
+ <UserButton />
178
+ </SignedIn>
179
+
180
+ <SignedOut>
181
+ <!-- Only shown when user is logged out -->
182
+ <SignIn />
183
+ </SignedOut>
184
+ ```
95
185
 
96
186
  ### UserButton
97
187
 
98
- User menu button that shows avatar/name and dropdown with profile/signout.
188
+ User menu button with avatar and logout.
99
189
 
100
190
  ```vue
101
- <script setup lang="ts">
102
- import { UserButton } from '@drmhse/authos-vue';
103
- </script>
104
-
105
- <template>
106
- <header>
107
- <UserButton />
108
- </header>
109
- </template>
191
+ <UserButton @logout="router.push('/')" />
110
192
  ```
111
193
 
112
194
  ### OrganizationSwitcher
113
195
 
114
- Dropdown to switch between organizations (for multi-tenant users).
196
+ Dropdown to switch between organizations.
115
197
 
116
- ```vue
117
- <script setup lang="ts">
118
- import { OrganizationSwitcher } from '@drmhse/authos-vue';
119
- </script>
198
+ When switching organizations, the SDK automatically issues new JWT tokens with the new organization context, enabling seamless multi-tenant switching without re-authentication.
120
199
 
121
- <template>
122
- <aside>
123
- <OrganizationSwitcher />
124
- </aside>
125
- </template>
200
+ ```vue
201
+ <OrganizationSwitcher @switch="org => console.log('Switched to:', org.name)" />
126
202
  ```
127
203
 
128
204
  ### Protect
@@ -130,68 +206,58 @@ import { OrganizationSwitcher } from '@drmhse/authos-vue';
130
206
  Conditional rendering based on user permissions.
131
207
 
132
208
  ```vue
133
- <script setup lang="ts">
134
- import { Protect } from '@drmhse/authos-vue';
135
- </script>
209
+ <Protect permission="admin:access">
210
+ <template #default>
211
+ <AdminDashboard />
212
+ </template>
213
+ <template #fallback>
214
+ <p>Access denied</p>
215
+ </template>
216
+ </Protect>
217
+ ```
136
218
 
137
- <template>
138
- <Protect permission="admin:access">
139
- <template #default>
140
- <AdminDashboard />
141
- </template>
142
- <template #fallback>
143
- <p>Access denied. Admins only.</p>
144
- </template>
145
- </Protect>
146
- </template>
219
+ ### OAuthButton
220
+
221
+ Individual OAuth provider button. Requires `org` and `service` in plugin options.
222
+
223
+ ```vue
224
+ <OAuthButton provider="github" />
225
+ <OAuthButton provider="google">Continue with Google</OAuthButton>
147
226
  ```
148
227
 
149
- **Props:**
150
- | Prop | Type | Description |
151
- |------|------|-------------|
152
- | `permission` | `string` | Required permission to access content |
153
- | `fallback` | `slot` | Shown when user lacks permission |
154
- | `default` | `slot` | Protected content |
228
+ **Scoped Slot:**
229
+ ```vue
230
+ <OAuthButton provider="github" v-slot="{ providerName, isConfigured, handleClick }">
231
+ <button @click="handleClick" :disabled="!isConfigured">
232
+ Continue with {{ providerName }}
233
+ </button>
234
+ </OAuthButton>
235
+ ```
155
236
 
156
237
  ## Composables
157
238
 
158
239
  ### useAuthOS
159
240
 
160
- Access the AuthOS client directly.
241
+ Access the AuthOS client, state, and configuration.
161
242
 
162
243
  ```vue
163
- <script setup lang="ts">
244
+ <script setup>
164
245
  import { useAuthOS } from '@drmhse/authos-vue';
165
246
 
166
- const { client, isAuthenticated, isLoading } = useAuthOS();
247
+ const { client, options, isAuthenticated, isLoading } = useAuthOS();
167
248
 
168
249
  async function handleLogout() {
169
250
  await client.auth.logout();
170
251
  }
171
252
  </script>
172
-
173
- <template>
174
- <div v-if="isLoading">Loading...</div>
175
- <div v-else-if="!isAuthenticated">Please log in</div>
176
- <div v-else>
177
- <button @click="handleLogout">Logout</button>
178
- </div>
179
- </template>
180
253
  ```
181
254
 
182
- **Returns:**
183
- | Property | Type | Description |
184
- |----------|------|-------------|
185
- | `client` | `SsoClient` | The AuthOS SDK client |
186
- | `isLoading` | `Ref<boolean>` | True while checking auth state |
187
- | `isAuthenticated` | `Ref<boolean>` | True if user is logged in |
188
-
189
255
  ### useUser
190
256
 
191
257
  Get the current user's profile.
192
258
 
193
259
  ```vue
194
- <script setup lang="ts">
260
+ <script setup>
195
261
  import { useUser } from '@drmhse/authos-vue';
196
262
 
197
263
  const { user, isLoading } = useUser();
@@ -203,73 +269,64 @@ const { user, isLoading } = useUser();
203
269
  </template>
204
270
  ```
205
271
 
206
- **Returns:**
207
- | Property | Type | Description |
208
- |----------|------|-------------|
209
- | `user` | `Ref<UserProfile | null>` | Current user profile |
210
- | `isLoading` | `Ref<boolean>` | True while checking auth state |
211
-
212
272
  ### useOrganization
213
273
 
214
- Get the current organization and list of organizations.
274
+ Get and switch between organizations.
215
275
 
216
276
  ```vue
217
- <script setup lang="ts">
277
+ <script setup>
218
278
  import { useOrganization } from '@drmhse/authos-vue';
219
279
 
220
- const { currentOrganization, organizations, switchOrganization } = useOrganization();
280
+ const { currentOrganization, organizations, switchOrganization, isSwitching } = useOrganization();
221
281
  </script>
222
282
 
223
283
  <template>
224
- <div>
225
- <h3>{{ currentOrganization?.name }}</h3>
226
- <ul>
227
- <li v-for="org in organizations" :key="org.id">
228
- {{ org.name }}
229
- </li>
230
- </ul>
231
- </div>
284
+ <h3>{{ currentOrganization?.name }}</h3>
285
+ <ul>
286
+ <li v-for="org in organizations" :key="org.id">
287
+ <button @click="switchOrganization(org.slug)">{{ org.name }}</button>
288
+ </li>
289
+ </ul>
232
290
  </template>
233
291
  ```
234
292
 
235
- **Returns:**
236
- | Property | Type | Description |
237
- |----------|------|-------------|
238
- | `currentOrganization` | `Ref<Organization | null>` | Current organization |
239
- | `organizations` | `Ref<Organization[]>` | All user's organizations |
240
- | `switchOrganization` | `(slug: string) => Promise<void>` | Switch to a different org |
241
- | `isSwitching` | `Ref<boolean>` | True while switching |
293
+ ### usePermission / useAnyPermission / useAllPermissions
242
294
 
243
- ## Nuxt Module
244
-
245
- When using the Nuxt module, the plugin is auto-installed and provides additional server utilities:
295
+ Check user permissions.
246
296
 
247
297
  ```vue
248
- <!-- app.vue -->
249
- <script setup lang="ts">
250
- // Plugin is auto-installed, composables work automatically
251
- import { useUser } from '@drmhse/authos-vue';
298
+ <script setup>
299
+ import { usePermission, useAnyPermission, useAllPermissions } from '@drmhse/authos-vue';
252
300
 
253
- const { user } = useUser();
301
+ const canAccessAdmin = usePermission('admin:access');
302
+ const canReadOrWrite = useAnyPermission(['read:data', 'write:data']);
303
+ const hasFullAccess = useAllPermissions(['read:data', 'write:data', 'delete:data']);
254
304
  </script>
255
305
 
256
306
  <template>
257
- <div v-if="user">
258
- Welcome, {{ user.email }}
259
- </div>
307
+ <button v-if="canAccessAdmin">Admin Panel</button>
260
308
  </template>
261
309
  ```
262
310
 
263
- ### Nuxt Auth Middleware
311
+ ## Nuxt Integration
264
312
 
265
- Protect pages with the auth middleware:
313
+ ### Plugin Installation
314
+
315
+ ```ts
316
+ // nuxt.config.ts
317
+ export default defineNuxtConfig({
318
+ modules: ['@drmhse/authos-vue/nuxt'],
319
+ });
320
+ ```
321
+
322
+ ### Auth Middleware
266
323
 
267
324
  ```ts
268
325
  // middleware/auth.ts
269
326
  import { authMiddleware } from '@drmhse/authos-vue/nuxt';
270
327
 
271
328
  export default authMiddleware({
272
- redirectTo: '/login'
329
+ redirectTo: '/login',
273
330
  });
274
331
  ```
275
332
 
@@ -278,7 +335,7 @@ Then use in your pages:
278
335
  ```vue
279
336
  <script setup>
280
337
  definePageMeta({
281
- middleware: ['auth']
338
+ middleware: ['auth'],
282
339
  });
283
340
  </script>
284
341
 
@@ -299,7 +356,7 @@ export default defineEventHandler(async (event) => {
299
356
  if (!user) {
300
357
  throw createError({
301
358
  statusCode: 401,
302
- message: 'Unauthorized'
359
+ message: 'Unauthorized',
303
360
  });
304
361
  }
305
362
 
@@ -307,30 +364,50 @@ export default defineEventHandler(async (event) => {
307
364
  });
308
365
  ```
309
366
 
310
- ## SsoClient API
311
-
312
- The underlying client from `@drmhse/sso-sdk`. See [SDK docs](https://www.npmjs.com/package/@drmhse/sso-sdk) for full API.
313
-
314
- ```ts
315
- const { client } = useAuthOS();
316
-
317
- // Authentication
318
- await client.auth.login({ email, password });
319
- await client.auth.logout();
320
- await client.auth.register({ email, password, org_slug });
367
+ ## Configuration Reference
368
+
369
+ ### createAuthOS Options
370
+
371
+ | Option | Type | Required | Description |
372
+ |--------|------|----------|-------------|
373
+ | `baseURL` | `string` | ✅ | AuthOS API URL |
374
+ | `org` | `string` | For OAuth | Organization slug for OAuth flows |
375
+ | `service` | `string` | For OAuth | Service slug for OAuth flows |
376
+ | `redirectUri` | `string` | - | OAuth redirect URI (defaults to origin + '/callback') |
377
+ | `afterSignInUrl` | `string` | - | Redirect URL after sign-in |
378
+ | `afterSignUpUrl` | `string` | - | Redirect URL after sign-up |
379
+ | `storage` | `TokenStorage` | - | Custom token storage |
380
+ | `autoRefresh` | `boolean` | - | Auto-refresh expired tokens (default: true) |
381
+ | `initialToken` | `string` | - | SSR token for hydration |
382
+
383
+ ## Styling
384
+
385
+ All components use data attributes for styling hooks:
386
+
387
+ ```css
388
+ [data-authos-signin] { /* Container */ }
389
+ [data-authos-field="email"] { /* Email field wrapper */ }
390
+ [data-authos-field="password"] { /* Password field wrapper */ }
391
+ [data-authos-submit] { /* Submit button */ }
392
+ [data-authos-error] { /* Error message */ }
393
+ [data-authos-oauth] { /* OAuth button */ }
394
+ [data-authos-oauth][data-provider="github"] { /* GitHub button */ }
395
+ [data-authos-divider] { /* "or" divider */ }
396
+ ```
321
397
 
322
- // User
323
- await client.user.getProfile();
324
- await client.user.updateProfile({ name });
325
- await client.user.changePassword({ old, new });
398
+ ## Migration from v1
326
399
 
327
- // Organizations
328
- await client.organizations.list();
329
- await client.organizations.get(slug);
400
+ If you're upgrading from v1, note the following breaking change:
330
401
 
331
- // And more...
402
+ ```diff
403
+ app.use(createAuthOS({
404
+ - baseUrl: 'https://sso.example.com',
405
+ + baseURL: 'https://sso.example.com',
406
+ }));
332
407
  ```
333
408
 
409
+ The `baseUrl` property has been renamed to `baseURL` (uppercase URL) for consistency with the React package and underlying SDK.
410
+
334
411
  ## License
335
412
 
336
413
  MIT © DRM HSE
@@ -6,12 +6,16 @@ var AUTH_OS_INJECTION_KEY = /* @__PURE__ */ Symbol("authOS");
6
6
  function useAuthOS() {
7
7
  const context = inject(AUTH_OS_INJECTION_KEY);
8
8
  if (!context) {
9
+ const defaultOptions = {
10
+ baseURL: "http://localhost:3001"
11
+ };
9
12
  const defaultClient = new SsoClient({
10
- baseURL: "http://localhost:3001",
13
+ baseURL: defaultOptions.baseURL,
11
14
  storage: new MemoryStorage()
12
15
  });
13
16
  return {
14
17
  client: defaultClient,
18
+ options: defaultOptions,
15
19
  isLoading: computed(() => false),
16
20
  isAuthenticated: computed(() => false)
17
21
  };
@@ -20,6 +24,7 @@ function useAuthOS() {
20
24
  const isAuthenticated = computed(() => context.state.isAuthenticated);
21
25
  return {
22
26
  client: context.client,
27
+ options: context.options,
23
28
  isLoading,
24
29
  isAuthenticated
25
30
  };