@drmhse/authos-vue 0.1.0 → 0.1.2

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 ADDED
@@ -0,0 +1,335 @@
1
+ # @drmhse/authos-vue
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@drmhse/authos-vue)](https://www.npmjs.com/package/@drmhse/authos-vue)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ Vue 3 adapter for [AuthOS](https://authos.dev) - the multi-tenant authentication platform. Provides Vue composables, components, and Nuxt module.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install @drmhse/authos-vue
12
+ ```
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:
24
+
25
+ ```ts
26
+ // main.ts
27
+ import { createApp } from 'vue';
28
+ import { createAuthOS } from '@drmhse/authos-vue';
29
+ import App from './App.vue';
30
+
31
+ const app = createApp(App);
32
+
33
+ app.use(createAuthOS({
34
+ baseUrl: 'https://sso.example.com'
35
+ }));
36
+
37
+ app.mount('#app');
38
+ ```
39
+
40
+ ### Nuxt App
41
+
42
+ ```ts
43
+ // nuxt.config.ts
44
+ export default defineNuxtConfig({
45
+ modules: ['@drmhse/authos-vue/nuxt']
46
+ });
47
+ ```
48
+
49
+ ## Components
50
+
51
+ ### SignIn
52
+
53
+ Pre-built sign-in form with email/password and OAuth provider buttons.
54
+
55
+ ```vue
56
+ <script setup lang="ts">
57
+ import { SignIn } from '@drmhse/authos-vue';
58
+
59
+ function handleSuccess() {
60
+ console.log('Logged in!');
61
+ }
62
+
63
+ function handleError(err: Error) {
64
+ console.error(err);
65
+ }
66
+ </script>
67
+
68
+ <template>
69
+ <SignIn @success="handleSuccess" @error="handleError" />
70
+ </template>
71
+ ```
72
+
73
+ **Events:**
74
+ | Event | Payload | Description |
75
+ |-------|---------|-------------|
76
+ | `@success` | - | Fired after successful login |
77
+ | `@error` | `Error` | Fired on login error |
78
+
79
+ ### SignUp
80
+
81
+ Registration form for new users.
82
+
83
+ ```vue
84
+ <script setup lang="ts">
85
+ import { SignUp } from '@drmhse/authos-vue';
86
+ </script>
87
+
88
+ <template>
89
+ <SignUp />
90
+ </template>
91
+ ```
92
+
93
+ **Events:** Same as `SignIn`
94
+
95
+ ### UserButton
96
+
97
+ User menu button that shows avatar/name and dropdown with profile/signout.
98
+
99
+ ```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>
109
+ ```
110
+
111
+ ### OrganizationSwitcher
112
+
113
+ Dropdown to switch between organizations (for multi-tenant users).
114
+
115
+ ```vue
116
+ <script setup lang="ts">
117
+ import { OrganizationSwitcher } from '@drmhse/authos-vue';
118
+ </script>
119
+
120
+ <template>
121
+ <aside>
122
+ <OrganizationSwitcher />
123
+ </aside>
124
+ </template>
125
+ ```
126
+
127
+ ### Protect
128
+
129
+ Conditional rendering based on user permissions.
130
+
131
+ ```vue
132
+ <script setup lang="ts">
133
+ import { Protect } from '@drmhse/authos-vue';
134
+ </script>
135
+
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>
146
+ ```
147
+
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 |
154
+
155
+ ## Composables
156
+
157
+ ### useAuthOS
158
+
159
+ Access the AuthOS client directly.
160
+
161
+ ```vue
162
+ <script setup lang="ts">
163
+ import { useAuthOS } from '@drmhse/authos-vue';
164
+
165
+ const { client, isAuthenticated, isLoading } = useAuthOS();
166
+
167
+ async function handleLogout() {
168
+ await client.auth.logout();
169
+ }
170
+ </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
+ ```
180
+
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
+ ### useUser
189
+
190
+ Get the current user's profile.
191
+
192
+ ```vue
193
+ <script setup lang="ts">
194
+ import { useUser } from '@drmhse/authos-vue';
195
+
196
+ const { user, isLoading } = useUser();
197
+ </script>
198
+
199
+ <template>
200
+ <div v-if="isLoading">Loading...</div>
201
+ <div v-else>Welcome, {{ user?.email }}</div>
202
+ </template>
203
+ ```
204
+
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
+ ### useOrganization
212
+
213
+ Get the current organization and list of organizations.
214
+
215
+ ```vue
216
+ <script setup lang="ts">
217
+ import { useOrganization } from '@drmhse/authos-vue';
218
+
219
+ const { currentOrganization, organizations, switchOrganization } = useOrganization();
220
+ </script>
221
+
222
+ <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>
231
+ </template>
232
+ ```
233
+
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 |
241
+
242
+ ## Nuxt Module
243
+
244
+ When using the Nuxt module, the plugin is auto-installed and provides additional server utilities:
245
+
246
+ ```vue
247
+ <!-- app.vue -->
248
+ <script setup lang="ts">
249
+ // Plugin is auto-installed, composables work automatically
250
+ import { useUser } from '@drmhse/authos-vue';
251
+
252
+ const { user } = useUser();
253
+ </script>
254
+
255
+ <template>
256
+ <div v-if="user">
257
+ Welcome, {{ user.email }}
258
+ </div>
259
+ </template>
260
+ ```
261
+
262
+ ### Nuxt Auth Middleware
263
+
264
+ Protect pages with the auth middleware:
265
+
266
+ ```ts
267
+ // middleware/auth.ts
268
+ import { authMiddleware } from '@drmhse/authos-vue/nuxt';
269
+
270
+ export default authMiddleware({
271
+ redirectTo: '/login'
272
+ });
273
+ ```
274
+
275
+ Then use in your pages:
276
+
277
+ ```vue
278
+ <script setup>
279
+ definePageMeta({
280
+ middleware: ['auth']
281
+ });
282
+ </script>
283
+
284
+ <template>
285
+ <div>Protected page</div>
286
+ </template>
287
+ ```
288
+
289
+ ### Server-Side Usage
290
+
291
+ ```ts
292
+ // server/api/user.get.ts
293
+ import { currentUser } from '@drmhse/authos-vue/nuxt';
294
+
295
+ export default defineEventHandler(async (event) => {
296
+ const user = await currentUser(event);
297
+
298
+ if (!user) {
299
+ throw createError({
300
+ statusCode: 401,
301
+ message: 'Unauthorized'
302
+ });
303
+ }
304
+
305
+ return user;
306
+ });
307
+ ```
308
+
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 });
320
+
321
+ // User
322
+ await client.user.getProfile();
323
+ await client.user.updateProfile({ name });
324
+ await client.user.changePassword({ old, new });
325
+
326
+ // Organizations
327
+ await client.organizations.list();
328
+ await client.organizations.get(slug);
329
+
330
+ // And more...
331
+ ```
332
+
333
+ ## License
334
+
335
+ MIT © DRM HSE
package/dist/index.d.mts CHANGED
@@ -19,6 +19,12 @@ interface AuthOSPluginOptions {
19
19
  baseUrl: string;
20
20
  storage?: TokenStorage;
21
21
  autoRefresh?: boolean;
22
+ /**
23
+ * Initial session token from server-side (for SSR hydration).
24
+ * When provided, skips the initial loading state on the client.
25
+ * Typically passed from cookies in Nuxt server components.
26
+ */
27
+ initialToken?: string;
22
28
  }
23
29
  declare const AUTH_OS_INJECTION_KEY: unique symbol;
24
30
 
package/dist/index.d.ts CHANGED
@@ -19,6 +19,12 @@ interface AuthOSPluginOptions {
19
19
  baseUrl: string;
20
20
  storage?: TokenStorage;
21
21
  autoRefresh?: boolean;
22
+ /**
23
+ * Initial session token from server-side (for SSR hydration).
24
+ * When provided, skips the initial loading state on the client.
25
+ * Typically passed from cookies in Nuxt server components.
26
+ */
27
+ initialToken?: string;
22
28
  }
23
29
  declare const AUTH_OS_INJECTION_KEY: unique symbol;
24
30
 
package/dist/index.js CHANGED
@@ -22,12 +22,22 @@ function createAuthOS(options) {
22
22
  };
23
23
  const client = new ssoSdk.SsoClient({
24
24
  baseURL: options.baseUrl,
25
- storage: getStorage()
25
+ storage: getStorage(),
26
+ token: options.initialToken
27
+ // Pass initial token if provided
26
28
  });
29
+ let hasSetInitialToken = false;
30
+ const setInitialToken = async () => {
31
+ if (options.initialToken && !hasSetInitialToken) {
32
+ await client.setSession({ access_token: options.initialToken });
33
+ hasSetInitialToken = true;
34
+ }
35
+ };
27
36
  const state = vue.reactive({
28
37
  user: null,
29
38
  isAuthenticated: false,
30
- isLoading: true,
39
+ isLoading: !options.initialToken,
40
+ // Skip loading if we have initial token
31
41
  currentOrganization: null,
32
42
  organizations: []
33
43
  });
@@ -37,6 +47,9 @@ function createAuthOS(options) {
37
47
  };
38
48
  return {
39
49
  install(app) {
50
+ vue.nextTick(() => {
51
+ setInitialToken();
52
+ });
40
53
  client.onAuthStateChange(async (isAuthenticated) => {
41
54
  state.isAuthenticated = isAuthenticated;
42
55
  state.isLoading = false;
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { AUTH_OS_INJECTION_KEY, useAuthOS } from './chunk-OGRUDANK.mjs';
2
2
  export { AUTH_OS_INJECTION_KEY, useAuthOS } from './chunk-OGRUDANK.mjs';
3
3
  import './chunk-6DZX6EAA.mjs';
4
- import { defineComponent, reactive, provide, onMounted, onUnmounted, h, ref, computed, inject } from 'vue';
4
+ import { defineComponent, reactive, provide, onMounted, onUnmounted, h, ref, computed, inject, nextTick } from 'vue';
5
5
  import { SsoClient, BrowserStorage, MemoryStorage, SsoApiError } from '@drmhse/sso-sdk';
6
6
  export { AuthErrorCodes, BrowserStorage, MemoryStorage, SsoApiError } from '@drmhse/sso-sdk';
7
7
 
@@ -18,12 +18,22 @@ function createAuthOS(options) {
18
18
  };
19
19
  const client = new SsoClient({
20
20
  baseURL: options.baseUrl,
21
- storage: getStorage()
21
+ storage: getStorage(),
22
+ token: options.initialToken
23
+ // Pass initial token if provided
22
24
  });
25
+ let hasSetInitialToken = false;
26
+ const setInitialToken = async () => {
27
+ if (options.initialToken && !hasSetInitialToken) {
28
+ await client.setSession({ access_token: options.initialToken });
29
+ hasSetInitialToken = true;
30
+ }
31
+ };
23
32
  const state = reactive({
24
33
  user: null,
25
34
  isAuthenticated: false,
26
- isLoading: true,
35
+ isLoading: !options.initialToken,
36
+ // Skip loading if we have initial token
27
37
  currentOrganization: null,
28
38
  organizations: []
29
39
  });
@@ -33,6 +43,9 @@ function createAuthOS(options) {
33
43
  };
34
44
  return {
35
45
  install(app) {
46
+ nextTick(() => {
47
+ setInitialToken();
48
+ });
36
49
  client.onAuthStateChange(async (isAuthenticated) => {
37
50
  state.isAuthenticated = isAuthenticated;
38
51
  state.isLoading = false;
package/dist/nuxt.d.mts CHANGED
@@ -3,6 +3,26 @@ import * as nuxt_app from 'nuxt/app';
3
3
 
4
4
  interface AuthOSModuleOptions {
5
5
  baseUrl: string;
6
+ /**
7
+ * Cookie name for storing the access token
8
+ * @default 'authos_token'
9
+ */
10
+ tokenCookie?: string;
11
+ /**
12
+ * Cookie domain (optional)
13
+ * Use this for subdomain-wide auth
14
+ */
15
+ domain?: string;
16
+ /**
17
+ * Cookie path
18
+ * @default '/'
19
+ */
20
+ path?: string;
21
+ /**
22
+ * SameSite cookie attribute
23
+ * @default 'lax'
24
+ */
25
+ sameSite?: 'strict' | 'lax' | 'none';
6
26
  }
7
27
  declare const _default: _nuxt_schema.NuxtModule<AuthOSModuleOptions, AuthOSModuleOptions, false>;
8
28
 
package/dist/nuxt.d.ts CHANGED
@@ -3,6 +3,26 @@ import * as nuxt_app from 'nuxt/app';
3
3
 
4
4
  interface AuthOSModuleOptions {
5
5
  baseUrl: string;
6
+ /**
7
+ * Cookie name for storing the access token
8
+ * @default 'authos_token'
9
+ */
10
+ tokenCookie?: string;
11
+ /**
12
+ * Cookie domain (optional)
13
+ * Use this for subdomain-wide auth
14
+ */
15
+ domain?: string;
16
+ /**
17
+ * Cookie path
18
+ * @default '/'
19
+ */
20
+ path?: string;
21
+ /**
22
+ * SameSite cookie attribute
23
+ * @default 'lax'
24
+ */
25
+ sameSite?: 'strict' | 'lax' | 'none';
6
26
  }
7
27
  declare const _default: _nuxt_schema.NuxtModule<AuthOSModuleOptions, AuthOSModuleOptions, false>;
8
28
 
package/dist/nuxt.js CHANGED
@@ -10464,12 +10464,19 @@ var module_default = defineNuxtModule({
10464
10464
  }
10465
10465
  },
10466
10466
  defaults: {
10467
- baseUrl: ""
10467
+ baseUrl: "",
10468
+ tokenCookie: "authos_token",
10469
+ path: "/",
10470
+ sameSite: "lax"
10468
10471
  },
10469
10472
  setup(options, nuxt) {
10470
10473
  const resolver = createResolver((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('nuxt.js', document.baseURI).href)));
10471
10474
  nuxt.options.runtimeConfig.public.authOS = {
10472
- baseUrl: options.baseUrl
10475
+ baseUrl: options.baseUrl,
10476
+ tokenCookie: options.tokenCookie,
10477
+ domain: options.domain,
10478
+ path: options.path,
10479
+ sameSite: options.sameSite
10473
10480
  };
10474
10481
  addPlugin(resolver.resolve("./runtime/plugin"));
10475
10482
  addImports([
package/dist/nuxt.mjs CHANGED
@@ -7953,12 +7953,19 @@ var module_default = defineNuxtModule({
7953
7953
  }
7954
7954
  },
7955
7955
  defaults: {
7956
- baseUrl: ""
7956
+ baseUrl: "",
7957
+ tokenCookie: "authos_token",
7958
+ path: "/",
7959
+ sameSite: "lax"
7957
7960
  },
7958
7961
  setup(options, nuxt) {
7959
7962
  const resolver = createResolver(import.meta.url);
7960
7963
  nuxt.options.runtimeConfig.public.authOS = {
7961
- baseUrl: options.baseUrl
7964
+ baseUrl: options.baseUrl,
7965
+ tokenCookie: options.tokenCookie,
7966
+ domain: options.domain,
7967
+ path: options.path,
7968
+ sameSite: options.sameSite
7962
7969
  };
7963
7970
  addPlugin(resolver.resolve("./runtime/plugin"));
7964
7971
  addImports([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drmhse/authos-vue",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Vue and Nuxt adapter for AuthOS authentication",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -35,7 +35,6 @@
35
35
  "dev": "tsup --watch",
36
36
  "typecheck": "vue-tsc --noEmit",
37
37
  "lint": "eslint src --ext .ts,.vue",
38
- "test:ct": "playwright test -c playwright-ct.config.ts --reporter=list",
39
38
  "prepublishOnly": "npm run build"
40
39
  },
41
40
  "keywords": [
@@ -53,8 +52,6 @@
53
52
  "vue": ">=3.4.0"
54
53
  },
55
54
  "devDependencies": {
56
- "@playwright/experimental-ct-vue": "^1.48.0",
57
- "@playwright/test": "^1.48.0",
58
55
  "@types/node": "^25.0.3",
59
56
  "nuxt": "^3.14.0",
60
57
  "tsup": "^8.3.5",