@drmhse/authos-vue 0.1.2 → 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,42 +22,122 @@ import App from './App.vue';
31
22
  const app = createApp(App);
32
23
 
33
24
  app.use(createAuthOS({
34
- baseUrl: 'https://sso.example.com'
25
+ baseURL: 'https://sso.example.com',
35
26
  }));
36
27
 
37
28
  app.mount('#app');
38
29
  ```
39
30
 
40
- ### 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`:
41
61
 
42
62
  ```ts
43
- // nuxt.config.ts
44
- export default defineNuxtConfig({
45
- 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,
46
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>
47
122
  ```
48
123
 
49
124
  ## Components
50
125
 
51
126
  ### SignIn
52
127
 
53
- 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.
54
129
 
55
130
  ```vue
56
- <script setup lang="ts">
131
+ <script setup>
57
132
  import { SignIn } from '@drmhse/authos-vue';
58
133
 
59
134
  function handleSuccess() {
60
- console.log('Logged in!');
61
- }
62
-
63
- function handleError(err: Error) {
64
- console.error(err);
135
+ router.push('/dashboard');
65
136
  }
66
137
  </script>
67
138
 
68
139
  <template>
69
- <SignIn @success="handleSuccess" @error="handleError" />
140
+ <SignIn @success="handleSuccess" @error="console.error" />
70
141
  </template>
71
142
  ```
72
143
 
@@ -76,52 +147,58 @@ function handleError(err: Error) {
76
147
  | `@success` | - | Fired after successful login |
77
148
  | `@error` | `Error` | Fired on login error |
78
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
+
79
162
  ### SignUp
80
163
 
81
164
  Registration form for new users.
82
165
 
83
166
  ```vue
84
- <script setup lang="ts">
85
- import { SignUp } from '@drmhse/authos-vue';
86
- </script>
87
-
88
- <template>
89
- <SignUp />
90
- </template>
167
+ <SignUp @success="console.log('Check your email!')" @error="console.error" />
91
168
  ```
92
169
 
93
- **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
+ ```
94
185
 
95
186
  ### UserButton
96
187
 
97
- User menu button that shows avatar/name and dropdown with profile/signout.
188
+ User menu button with avatar and logout.
98
189
 
99
190
  ```vue
100
- <script setup lang="ts">
101
- import { UserButton } from '@drmhse/authos-vue';
102
- </script>
103
-
104
- <template>
105
- <header>
106
- <UserButton />
107
- </header>
108
- </template>
191
+ <UserButton @logout="router.push('/')" />
109
192
  ```
110
193
 
111
194
  ### OrganizationSwitcher
112
195
 
113
- Dropdown to switch between organizations (for multi-tenant users).
196
+ Dropdown to switch between organizations.
114
197
 
115
- ```vue
116
- <script setup lang="ts">
117
- import { OrganizationSwitcher } from '@drmhse/authos-vue';
118
- </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.
119
199
 
120
- <template>
121
- <aside>
122
- <OrganizationSwitcher />
123
- </aside>
124
- </template>
200
+ ```vue
201
+ <OrganizationSwitcher @switch="org => console.log('Switched to:', org.name)" />
125
202
  ```
126
203
 
127
204
  ### Protect
@@ -129,68 +206,58 @@ import { OrganizationSwitcher } from '@drmhse/authos-vue';
129
206
  Conditional rendering based on user permissions.
130
207
 
131
208
  ```vue
132
- <script setup lang="ts">
133
- import { Protect } from '@drmhse/authos-vue';
134
- </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
+ ```
135
218
 
136
- <template>
137
- <Protect permission="admin:access">
138
- <template #default>
139
- <AdminDashboard />
140
- </template>
141
- <template #fallback>
142
- <p>Access denied. Admins only.</p>
143
- </template>
144
- </Protect>
145
- </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>
146
226
  ```
147
227
 
148
- **Props:**
149
- | Prop | Type | Description |
150
- |------|------|-------------|
151
- | `permission` | `string` | Required permission to access content |
152
- | `fallback` | `slot` | Shown when user lacks permission |
153
- | `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
+ ```
154
236
 
155
237
  ## Composables
156
238
 
157
239
  ### useAuthOS
158
240
 
159
- Access the AuthOS client directly.
241
+ Access the AuthOS client, state, and configuration.
160
242
 
161
243
  ```vue
162
- <script setup lang="ts">
244
+ <script setup>
163
245
  import { useAuthOS } from '@drmhse/authos-vue';
164
246
 
165
- const { client, isAuthenticated, isLoading } = useAuthOS();
247
+ const { client, options, isAuthenticated, isLoading } = useAuthOS();
166
248
 
167
249
  async function handleLogout() {
168
250
  await client.auth.logout();
169
251
  }
170
252
  </script>
171
-
172
- <template>
173
- <div v-if="isLoading">Loading...</div>
174
- <div v-else-if="!isAuthenticated">Please log in</div>
175
- <div v-else>
176
- <button @click="handleLogout">Logout</button>
177
- </div>
178
- </template>
179
253
  ```
180
254
 
181
- **Returns:**
182
- | Property | Type | Description |
183
- |----------|------|-------------|
184
- | `client` | `SsoClient` | The AuthOS SDK client |
185
- | `isLoading` | `Ref<boolean>` | True while checking auth state |
186
- | `isAuthenticated` | `Ref<boolean>` | True if user is logged in |
187
-
188
255
  ### useUser
189
256
 
190
257
  Get the current user's profile.
191
258
 
192
259
  ```vue
193
- <script setup lang="ts">
260
+ <script setup>
194
261
  import { useUser } from '@drmhse/authos-vue';
195
262
 
196
263
  const { user, isLoading } = useUser();
@@ -202,73 +269,64 @@ const { user, isLoading } = useUser();
202
269
  </template>
203
270
  ```
204
271
 
205
- **Returns:**
206
- | Property | Type | Description |
207
- |----------|------|-------------|
208
- | `user` | `Ref<UserProfile | null>` | Current user profile |
209
- | `isLoading` | `Ref<boolean>` | True while checking auth state |
210
-
211
272
  ### useOrganization
212
273
 
213
- Get the current organization and list of organizations.
274
+ Get and switch between organizations.
214
275
 
215
276
  ```vue
216
- <script setup lang="ts">
277
+ <script setup>
217
278
  import { useOrganization } from '@drmhse/authos-vue';
218
279
 
219
- const { currentOrganization, organizations, switchOrganization } = useOrganization();
280
+ const { currentOrganization, organizations, switchOrganization, isSwitching } = useOrganization();
220
281
  </script>
221
282
 
222
283
  <template>
223
- <div>
224
- <h3>{{ currentOrganization?.name }}</h3>
225
- <ul>
226
- <li v-for="org in organizations" :key="org.id">
227
- {{ org.name }}
228
- </li>
229
- </ul>
230
- </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>
231
290
  </template>
232
291
  ```
233
292
 
234
- **Returns:**
235
- | Property | Type | Description |
236
- |----------|------|-------------|
237
- | `currentOrganization` | `Ref<Organization | null>` | Current organization |
238
- | `organizations` | `Ref<Organization[]>` | All user's organizations |
239
- | `switchOrganization` | `(slug: string) => Promise<void>` | Switch to a different org |
240
- | `isSwitching` | `Ref<boolean>` | True while switching |
293
+ ### usePermission / useAnyPermission / useAllPermissions
241
294
 
242
- ## Nuxt Module
243
-
244
- When using the Nuxt module, the plugin is auto-installed and provides additional server utilities:
295
+ Check user permissions.
245
296
 
246
297
  ```vue
247
- <!-- app.vue -->
248
- <script setup lang="ts">
249
- // Plugin is auto-installed, composables work automatically
250
- import { useUser } from '@drmhse/authos-vue';
298
+ <script setup>
299
+ import { usePermission, useAnyPermission, useAllPermissions } from '@drmhse/authos-vue';
251
300
 
252
- 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']);
253
304
  </script>
254
305
 
255
306
  <template>
256
- <div v-if="user">
257
- Welcome, {{ user.email }}
258
- </div>
307
+ <button v-if="canAccessAdmin">Admin Panel</button>
259
308
  </template>
260
309
  ```
261
310
 
262
- ### Nuxt Auth Middleware
311
+ ## Nuxt Integration
263
312
 
264
- 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
265
323
 
266
324
  ```ts
267
325
  // middleware/auth.ts
268
326
  import { authMiddleware } from '@drmhse/authos-vue/nuxt';
269
327
 
270
328
  export default authMiddleware({
271
- redirectTo: '/login'
329
+ redirectTo: '/login',
272
330
  });
273
331
  ```
274
332
 
@@ -277,7 +335,7 @@ Then use in your pages:
277
335
  ```vue
278
336
  <script setup>
279
337
  definePageMeta({
280
- middleware: ['auth']
338
+ middleware: ['auth'],
281
339
  });
282
340
  </script>
283
341
 
@@ -298,7 +356,7 @@ export default defineEventHandler(async (event) => {
298
356
  if (!user) {
299
357
  throw createError({
300
358
  statusCode: 401,
301
- message: 'Unauthorized'
359
+ message: 'Unauthorized',
302
360
  });
303
361
  }
304
362
 
@@ -306,30 +364,50 @@ export default defineEventHandler(async (event) => {
306
364
  });
307
365
  ```
308
366
 
309
- ## SsoClient API
310
-
311
- The underlying client from `@drmhse/sso-sdk`. See [SDK docs](https://www.npmjs.com/package/@drmhse/sso-sdk) for full API.
312
-
313
- ```ts
314
- const { client } = useAuthOS();
315
-
316
- // Authentication
317
- await client.auth.login({ email, password });
318
- await client.auth.logout();
319
- 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
+ ```
320
397
 
321
- // User
322
- await client.user.getProfile();
323
- await client.user.updateProfile({ name });
324
- await client.user.changePassword({ old, new });
398
+ ## Migration from v1
325
399
 
326
- // Organizations
327
- await client.organizations.list();
328
- await client.organizations.get(slug);
400
+ If you're upgrading from v1, note the following breaking change:
329
401
 
330
- // And more...
402
+ ```diff
403
+ app.use(createAuthOS({
404
+ - baseUrl: 'https://sso.example.com',
405
+ + baseURL: 'https://sso.example.com',
406
+ }));
331
407
  ```
332
408
 
409
+ The `baseUrl` property has been renamed to `baseURL` (uppercase URL) for consistency with the React package and underlying SDK.
410
+
333
411
  ## License
334
412
 
335
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
  };