@peterbud/nuxt-aegis 1.1.0-alpha

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.
Files changed (134) hide show
  1. package/README.md +166 -0
  2. package/dist/module.d.mts +6 -0
  3. package/dist/module.json +9 -0
  4. package/dist/module.mjs +354 -0
  5. package/dist/runtime/app/composables/useAuth.d.ts +85 -0
  6. package/dist/runtime/app/composables/useAuth.js +187 -0
  7. package/dist/runtime/app/middleware/auth-logged-in.d.ts +16 -0
  8. package/dist/runtime/app/middleware/auth-logged-in.js +25 -0
  9. package/dist/runtime/app/middleware/auth-logged-out.d.ts +20 -0
  10. package/dist/runtime/app/middleware/auth-logged-out.js +17 -0
  11. package/dist/runtime/app/pages/AuthCallback.d.vue.ts +3 -0
  12. package/dist/runtime/app/pages/AuthCallback.vue +92 -0
  13. package/dist/runtime/app/pages/AuthCallback.vue.d.ts +3 -0
  14. package/dist/runtime/app/plugins/api.client.d.ts +11 -0
  15. package/dist/runtime/app/plugins/api.client.js +92 -0
  16. package/dist/runtime/app/plugins/api.server.d.ts +13 -0
  17. package/dist/runtime/app/plugins/api.server.js +28 -0
  18. package/dist/runtime/app/plugins/ssr-state.server.d.ts +2 -0
  19. package/dist/runtime/app/plugins/ssr-state.server.js +13 -0
  20. package/dist/runtime/app/router.options.d.ts +12 -0
  21. package/dist/runtime/app/router.options.js +11 -0
  22. package/dist/runtime/app/utils/logger.d.ts +18 -0
  23. package/dist/runtime/app/utils/logger.js +48 -0
  24. package/dist/runtime/app/utils/redirectValidation.d.ts +18 -0
  25. package/dist/runtime/app/utils/redirectValidation.js +21 -0
  26. package/dist/runtime/app/utils/routeMatching.d.ts +13 -0
  27. package/dist/runtime/app/utils/routeMatching.js +10 -0
  28. package/dist/runtime/app/utils/tokenStore.d.ts +24 -0
  29. package/dist/runtime/app/utils/tokenStore.js +14 -0
  30. package/dist/runtime/app/utils/tokenUtils.d.ts +17 -0
  31. package/dist/runtime/app/utils/tokenUtils.js +4 -0
  32. package/dist/runtime/server/middleware/auth.d.ts +6 -0
  33. package/dist/runtime/server/middleware/auth.js +82 -0
  34. package/dist/runtime/server/plugins/ssr-auth.d.ts +7 -0
  35. package/dist/runtime/server/plugins/ssr-auth.js +82 -0
  36. package/dist/runtime/server/providers/auth0.d.ts +12 -0
  37. package/dist/runtime/server/providers/auth0.js +57 -0
  38. package/dist/runtime/server/providers/github.d.ts +12 -0
  39. package/dist/runtime/server/providers/github.js +44 -0
  40. package/dist/runtime/server/providers/google.d.ts +12 -0
  41. package/dist/runtime/server/providers/google.js +46 -0
  42. package/dist/runtime/server/providers/mock.d.ts +37 -0
  43. package/dist/runtime/server/providers/mock.js +129 -0
  44. package/dist/runtime/server/providers/oauthBase.d.ts +72 -0
  45. package/dist/runtime/server/providers/oauthBase.js +183 -0
  46. package/dist/runtime/server/routes/impersonate.post.d.ts +21 -0
  47. package/dist/runtime/server/routes/impersonate.post.js +68 -0
  48. package/dist/runtime/server/routes/logout.post.d.ts +9 -0
  49. package/dist/runtime/server/routes/logout.post.js +24 -0
  50. package/dist/runtime/server/routes/me.get.d.ts +6 -0
  51. package/dist/runtime/server/routes/me.get.js +11 -0
  52. package/dist/runtime/server/routes/mock/authorize.get.d.ts +29 -0
  53. package/dist/runtime/server/routes/mock/authorize.get.js +103 -0
  54. package/dist/runtime/server/routes/mock/token.post.d.ts +31 -0
  55. package/dist/runtime/server/routes/mock/token.post.js +88 -0
  56. package/dist/runtime/server/routes/mock/userinfo.get.d.ts +27 -0
  57. package/dist/runtime/server/routes/mock/userinfo.get.js +59 -0
  58. package/dist/runtime/server/routes/password/change.post.d.ts +4 -0
  59. package/dist/runtime/server/routes/password/change.post.js +108 -0
  60. package/dist/runtime/server/routes/password/login-verify.get.d.ts +2 -0
  61. package/dist/runtime/server/routes/password/login-verify.get.js +79 -0
  62. package/dist/runtime/server/routes/password/login.post.d.ts +4 -0
  63. package/dist/runtime/server/routes/password/login.post.js +66 -0
  64. package/dist/runtime/server/routes/password/register-verify.get.d.ts +2 -0
  65. package/dist/runtime/server/routes/password/register-verify.get.js +86 -0
  66. package/dist/runtime/server/routes/password/register.post.d.ts +4 -0
  67. package/dist/runtime/server/routes/password/register.post.js +87 -0
  68. package/dist/runtime/server/routes/password/reset-complete.post.d.ts +4 -0
  69. package/dist/runtime/server/routes/password/reset-complete.post.js +75 -0
  70. package/dist/runtime/server/routes/password/reset-request.post.d.ts +5 -0
  71. package/dist/runtime/server/routes/password/reset-request.post.js +52 -0
  72. package/dist/runtime/server/routes/password/reset-verify.get.d.ts +2 -0
  73. package/dist/runtime/server/routes/password/reset-verify.get.js +50 -0
  74. package/dist/runtime/server/routes/refresh.post.d.ts +8 -0
  75. package/dist/runtime/server/routes/refresh.post.js +102 -0
  76. package/dist/runtime/server/routes/token.post.d.ts +28 -0
  77. package/dist/runtime/server/routes/token.post.js +90 -0
  78. package/dist/runtime/server/routes/unimpersonate.post.d.ts +16 -0
  79. package/dist/runtime/server/routes/unimpersonate.post.js +65 -0
  80. package/dist/runtime/server/tsconfig.json +3 -0
  81. package/dist/runtime/server/utils/auth.d.ts +94 -0
  82. package/dist/runtime/server/utils/auth.js +54 -0
  83. package/dist/runtime/server/utils/authCodeStore.d.ts +137 -0
  84. package/dist/runtime/server/utils/authCodeStore.js +123 -0
  85. package/dist/runtime/server/utils/cookies.d.ts +15 -0
  86. package/dist/runtime/server/utils/cookies.js +23 -0
  87. package/dist/runtime/server/utils/customClaims.d.ts +37 -0
  88. package/dist/runtime/server/utils/customClaims.js +45 -0
  89. package/dist/runtime/server/utils/handler.d.ts +77 -0
  90. package/dist/runtime/server/utils/handler.js +7 -0
  91. package/dist/runtime/server/utils/impersonation.d.ts +48 -0
  92. package/dist/runtime/server/utils/impersonation.js +259 -0
  93. package/dist/runtime/server/utils/jwt.d.ts +24 -0
  94. package/dist/runtime/server/utils/jwt.js +77 -0
  95. package/dist/runtime/server/utils/logger.d.ts +18 -0
  96. package/dist/runtime/server/utils/logger.js +49 -0
  97. package/dist/runtime/server/utils/magicCodeStore.d.ts +27 -0
  98. package/dist/runtime/server/utils/magicCodeStore.js +66 -0
  99. package/dist/runtime/server/utils/mockCodeStore.d.ts +89 -0
  100. package/dist/runtime/server/utils/mockCodeStore.js +71 -0
  101. package/dist/runtime/server/utils/password.d.ts +33 -0
  102. package/dist/runtime/server/utils/password.js +48 -0
  103. package/dist/runtime/server/utils/refreshToken.d.ts +74 -0
  104. package/dist/runtime/server/utils/refreshToken.js +108 -0
  105. package/dist/runtime/server/utils/resetSessionStore.d.ts +12 -0
  106. package/dist/runtime/server/utils/resetSessionStore.js +29 -0
  107. package/dist/runtime/tasks/cleanup/magic-codes.d.ts +10 -0
  108. package/dist/runtime/tasks/cleanup/magic-codes.js +79 -0
  109. package/dist/runtime/tasks/cleanup/refresh-tokens.d.ts +10 -0
  110. package/dist/runtime/tasks/cleanup/refresh-tokens.js +55 -0
  111. package/dist/runtime/tasks/cleanup/reset-sessions.d.ts +8 -0
  112. package/dist/runtime/tasks/cleanup/reset-sessions.js +45 -0
  113. package/dist/runtime/types/augmentation.d.ts +73 -0
  114. package/dist/runtime/types/augmentation.js +0 -0
  115. package/dist/runtime/types/authCode.d.ts +60 -0
  116. package/dist/runtime/types/authCode.js +0 -0
  117. package/dist/runtime/types/callbacks.d.ts +54 -0
  118. package/dist/runtime/types/callbacks.js +0 -0
  119. package/dist/runtime/types/config.d.ts +129 -0
  120. package/dist/runtime/types/config.js +0 -0
  121. package/dist/runtime/types/hooks.d.ts +118 -0
  122. package/dist/runtime/types/hooks.js +0 -0
  123. package/dist/runtime/types/index.d.ts +13 -0
  124. package/dist/runtime/types/index.js +1 -0
  125. package/dist/runtime/types/providers.d.ts +212 -0
  126. package/dist/runtime/types/providers.js +0 -0
  127. package/dist/runtime/types/refresh.d.ts +61 -0
  128. package/dist/runtime/types/refresh.js +0 -0
  129. package/dist/runtime/types/routes.d.ts +30 -0
  130. package/dist/runtime/types/routes.js +0 -0
  131. package/dist/runtime/types/token.d.ts +182 -0
  132. package/dist/runtime/types/token.js +0 -0
  133. package/dist/types.d.mts +7 -0
  134. package/package.json +80 -0
package/README.md ADDED
@@ -0,0 +1,166 @@
1
+ # Nuxt Aegis
2
+
3
+ [![Build](https://github.com/peterbud/nuxt-aegis/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/peterbud/nuxt-aegis/actions/workflows/ci.yml)
4
+ [![npm version][npm-version-src]][npm-version-href]
5
+ [![npm downloads][npm-downloads-src]][npm-downloads-href]
6
+ [![License][license-src]][license-href]
7
+ [![Nuxt][nuxt-src]][nuxt-href]
8
+
9
+ **OAuth-based authentication with JWT token management for Nuxt 3/4**
10
+
11
+ > [!WARNING]
12
+ > **Experimental Module**: Nuxt Aegis is currently in active development and should be considered as work in progress. It is **not recommended for production use** at this time. APIs and features may change without notice.
13
+
14
+ Nuxt Aegis is a a Nuxt module that orchestrates the authentication flow between external identity providers (Google, GitHub, Auth0, etc.) and your application. It handles the complexity of OAuth 2.0, JWT token generation, and automatic token refresh, letting you focus on your application logic.
15
+
16
+
17
+ ## Why Nuxt Aegis?
18
+
19
+ Unlike cookie-based solutions that lock your API to the browser, Nuxt Aegis uses **industry-standard JWT bearer tokens**. This means your API is ready for:
20
+ - 📱 Mobile applications
21
+ - 🖥️ CLI tools
22
+ - 🌐 Third-party integrations
23
+ - ⚡ Universal access across platforms
24
+
25
+ ### How It Works
26
+
27
+ 1. **Authentication (Identity) Provider** (e.g., Google) authenticates the user.
28
+ 2. **Nuxt Aegis** verifies the identity retrieves the user information, and issues it's own application specific JWT.
29
+ 3. **Your App** receives the JWT token and uses it for authorization.
30
+
31
+ You get full control over user data persistence while Aegis handles the security lifecycle.
32
+
33
+ ## ✨ Key Features
34
+
35
+ - 🔐 **OAuth 2.0 & OpenID Connect** - Built-in support for Google, GitHub, Auth0, and Microsoft Entra ID.
36
+ - 🔑 **Password Authentication** - Secure username/password flow with magic link verification.
37
+ - 🎫 **JWT Management** - Automatic token generation, validation, and signing (HS256/RS256).
38
+ - 🔄 **Auto-Refresh** - Seamless background token refresh with secure HTTP-only cookies.
39
+ - 🛡️ **Route Protection** - Declarative middleware for both server API routes and client-side pages.
40
+ - 🧪 **Mock Provider** - Built-in testing provider to simulate auth flows without external services.
41
+ - 🎨 **Custom Claims** - Easily inject application-specific data (roles, permissions or similar) into tokens.
42
+ - 🎭 **Impersonation** - Support for user impersonation with full audit logging
43
+ - ⚙️ **SSR Friendly** - Works seamlessly with Nuxt's server-side rendering.
44
+ - 🥽 **Type Safe** - Written in TypeScript with full type definitions for a great developer experience.
45
+
46
+ ## 🚀 Quick Start
47
+
48
+ ### 1. Install
49
+
50
+ ```bash
51
+ npx nuxi module add nuxt-aegis
52
+ ```
53
+
54
+ ### 2. Configure
55
+
56
+ Add the module and provider configuration to `nuxt.config.ts`:
57
+
58
+ ```typescript
59
+ export default defineNuxtConfig({
60
+ modules: ['nuxt-aegis'],
61
+
62
+ nuxtAegis: {
63
+ token: {
64
+ secret: process.env.NUXT_AEGIS_TOKEN_SECRET!,
65
+ },
66
+ providers: {
67
+ google: {
68
+ clientId: process.env.GOOGLE_CLIENT_ID!,
69
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
70
+ },
71
+ },
72
+ },
73
+ })
74
+ ```
75
+
76
+ ### 3. Create Auth Route
77
+
78
+ Create a server route handler to initialize the provider:
79
+
80
+ ```typescript
81
+ // server/routes/auth/google.get.ts
82
+ export default defineOAuthGoogleEventHandler({
83
+ onUserInfo: (providerUserInfo, _tokens, _event) => {
84
+ return {
85
+ id: providerUserInfo.sub as string,
86
+ email: providerUserInfo.email,
87
+ name: providerUserInfo.name,
88
+ }
89
+ },
90
+ })
91
+ ```
92
+
93
+ ### 4. Use in Components
94
+
95
+ Access authentication state anywhere in your app:
96
+
97
+ ```vue
98
+ <script setup lang="ts">
99
+ const { user, isLoggedIn, login, logout } = useAuth()
100
+ </script>
101
+
102
+ <template>
103
+ <div v-if="isLoggedIn">
104
+ <h1>Welcome, {{ user?.name }}!</h1>
105
+ <button @click="logout()">Logout</button>
106
+ </div>
107
+ <button v-else @click="login('google')">
108
+ Login with Google
109
+ </button>
110
+ </template>
111
+ ```
112
+
113
+ ## 📖 Documentation
114
+
115
+ Ready to dive deeper? Check out the full documentation:
116
+
117
+ - **[Getting Started](./docs/getting-started/installation.md)** - Installation and setup guides.
118
+ - **[Providers](./docs/providers/)** - Configure Google, GitHub, Auth0, Password, and Mock providers.
119
+ - **[Route Protection](./docs/guides/route-protection.md)** - Learn how to protect your pages and API routes.
120
+ - **[Custom Claims](./docs/guides/custom-claims.md)** - Add custom data to your JWTs.
121
+ - **[API Reference](./docs/api/)** - Detailed API documentation.
122
+
123
+ ## Contributing
124
+
125
+ Contributions are welcome! Please see the [Requirements Specification](/specs/requirements.md) for detailed technical requirements.
126
+
127
+ ## Development
128
+
129
+ ```bash
130
+ # Install dependencies
131
+ pnpm install
132
+
133
+ # Start development server
134
+ pnpm dev
135
+
136
+ # Run tests
137
+ pnpm test
138
+
139
+ # Lint & type check
140
+ pnpm lint
141
+ ```
142
+
143
+ ## License
144
+
145
+ [MIT License](./LICENSE)
146
+
147
+ ## Acknowledgments
148
+
149
+ - Built with [Nuxt Module Builder](https://github.com/nuxt/module-builder)
150
+ - JWT handling powered by [jose](https://github.com/panva/jose)
151
+ - Heavily inspired by the [nuxt-auth-utils](https://github.com/atinux/nuxt-auth-utils) and Nuxt community
152
+
153
+ Made with ❤️ for the Nuxt community
154
+
155
+ <!-- Badges -->
156
+ [npm-version-src]: https://img.shields.io/npm/v/nuxt-aegis/latest.svg\?style\=flat\&colorA\=020420\&colorB\=00DC82
157
+ [npm-version-href]: https://npmjs.com/package/@peterbud/nuxt-aegis
158
+
159
+ [npm-downloads-src]: https://img.shields.io/npm/dm/nuxt-aegis.svg\?style\=flat\&colorA\=020420\&colorB\=00DC82
160
+ [npm-downloads-href]: https://npm.chart.dev/@peterbud/nuxt-aegis
161
+
162
+ [license-src]: https://img.shields.io/npm/l/nuxt-aegis.svg\?style\=flat\&colorA\=020420\&colorB\=00DC82
163
+ [license-href]: https://npmjs.com/package/@peterbud/nuxt-aegis
164
+
165
+ [nuxt-src]: https://img.shields.io/badge/Nuxt-020420\?logo\=nuxt.js
166
+ [nuxt-href]: https://nuxt.com
@@ -0,0 +1,6 @@
1
+ import * as _nuxt_schema from '@nuxt/schema';
2
+ import { ModuleOptions } from '../dist/runtime/types/index.js';
3
+
4
+ declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
5
+
6
+ export { _default as default };
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "nuxt-aegis",
3
+ "configKey": "nuxtAegis",
4
+ "version": "1.1.0-alpha",
5
+ "builder": {
6
+ "@nuxt/module-builder": "1.0.2",
7
+ "unbuild": "unknown"
8
+ }
9
+ }
@@ -0,0 +1,354 @@
1
+ import { defineNuxtModule, updateRuntimeConfig, useLogger, createResolver, addPlugin, addImports, extendPages, addServerImportsDir, addServerImports, addServerHandler, addServerPlugin, addRouteMiddleware, addTemplate } from '@nuxt/kit';
2
+ import { defu } from 'defu';
3
+
4
+ const module$1 = defineNuxtModule({
5
+ meta: {
6
+ name: "nuxt-aegis",
7
+ configKey: "nuxtAegis"
8
+ },
9
+ // Default configuration options of the Nuxt module
10
+ defaults: {
11
+ devtools: true,
12
+ token: {
13
+ secret: "",
14
+ // Must be provided by user or generated
15
+ expiresIn: "1h",
16
+ // Access token expiry
17
+ algorithm: "HS256",
18
+ issuer: "nuxt-aegis",
19
+ audience: ""
20
+ },
21
+ tokenRefresh: {
22
+ enabled: true,
23
+ automaticRefresh: true,
24
+ cookie: {
25
+ cookieName: "nuxt-aegis-refresh",
26
+ maxAge: 60 * 60 * 24 * 7,
27
+ // 7 days
28
+ secure: true,
29
+ sameSite: "lax",
30
+ httpOnly: true,
31
+ path: "/"
32
+ },
33
+ encryption: {
34
+ enabled: false,
35
+ // SC-16: Encryption disabled by default
36
+ algorithm: "aes-256-gcm"
37
+ // SC-17: Default encryption algorithm
38
+ },
39
+ storage: {
40
+ driver: "fs",
41
+ // RS-10: Default to filesystem storage
42
+ prefix: "refresh:",
43
+ base: "./.data/refresh-tokens"
44
+ },
45
+ ssrTokenExpiry: "5m"
46
+ // SSR token expiry (short-lived)
47
+ },
48
+ authCode: {
49
+ expiresIn: 60
50
+ // CS-4, CF-9: Authorization code expiry in seconds (default 60s)
51
+ },
52
+ redirect: {
53
+ logout: "/",
54
+ success: "/",
55
+ error: "/"
56
+ },
57
+ clientMiddleware: {
58
+ enabled: false,
59
+ global: false,
60
+ redirectTo: "/login",
61
+ loggedOutRedirectTo: "/",
62
+ publicRoutes: []
63
+ },
64
+ endpoints: {
65
+ authPath: "/auth",
66
+ loginPath: "/auth",
67
+ callbackPath: "/auth/callback",
68
+ logoutPath: "/auth/logout",
69
+ refreshPath: "/auth/refresh",
70
+ userInfoPath: "/api/user/me"
71
+ },
72
+ logging: {
73
+ level: "info",
74
+ security: false
75
+ }
76
+ },
77
+ setup(options, nuxt) {
78
+ options.enableSSR = options.enableSSR ?? (nuxt.options.ssr === true ? true : false);
79
+ updateRuntimeConfig({
80
+ public: {
81
+ nuxtAegis: {
82
+ authPath: options.endpoints?.authPath || "/auth",
83
+ loginPath: options.endpoints?.loginPath || options.endpoints?.authPath || "/auth",
84
+ callbackPath: options.endpoints?.callbackPath || "/auth/callback",
85
+ logoutPath: options.endpoints?.logoutPath || "/auth/logout",
86
+ refreshPath: options.endpoints?.refreshPath || "/auth/refresh",
87
+ userInfoPath: options.endpoints?.userInfoPath || "/api/user/me",
88
+ redirect: options.redirect,
89
+ tokenRefresh: options.tokenRefresh,
90
+ clientMiddleware: options.clientMiddleware,
91
+ logging: options.logging,
92
+ enableSSR: options.enableSSR
93
+ }
94
+ },
95
+ nuxtAegis: options
96
+ });
97
+ const runtimeConfig = nuxt.options.runtimeConfig;
98
+ if (options.enableSSR && nuxt.options.ssr === false) {
99
+ const logger2 = useLogger("nuxt-aegis");
100
+ logger2.warn(
101
+ "nuxtAegis.enableSSR is true but Nuxt SSR is disabled. SSR authentication will not work. Set ssr: true in nuxt.config.ts or disable enableSSR."
102
+ );
103
+ }
104
+ const resolver = createResolver(import.meta.url);
105
+ if (options.tokenRefresh?.encryption?.enabled) {
106
+ const encryptionKey = options.tokenRefresh.encryption.key || process.env.NUXT_AEGIS_ENCRYPTION_KEY;
107
+ if (!encryptionKey) {
108
+ throw new Error(
109
+ "[Nuxt Aegis] Encryption is enabled but no encryption key is configured. Please set tokenRefresh.encryption.key in nuxt.config.ts or NUXT_AEGIS_ENCRYPTION_KEY environment variable."
110
+ );
111
+ }
112
+ if (!runtimeConfig.nuxtAegis) {
113
+ runtimeConfig.nuxtAegis = {};
114
+ }
115
+ if (!runtimeConfig.nuxtAegis.tokenRefresh) {
116
+ runtimeConfig.nuxtAegis.tokenRefresh = {};
117
+ }
118
+ if (!runtimeConfig.nuxtAegis.tokenRefresh.encryption) {
119
+ runtimeConfig.nuxtAegis.tokenRefresh.encryption = {};
120
+ }
121
+ runtimeConfig.nuxtAegis.tokenRefresh.encryption.key = encryptionKey;
122
+ }
123
+ addPlugin(resolver.resolve("./runtime/app/plugins/api.client"));
124
+ addImports([
125
+ {
126
+ name: "useAuth",
127
+ from: resolver.resolve("./runtime/app/composables/useAuth")
128
+ }
129
+ ]);
130
+ extendPages((pages) => {
131
+ pages.push({
132
+ name: "Callback",
133
+ path: `${runtimeConfig.nuxtAegis?.endpoints?.callbackPath}` || `${runtimeConfig.public.nuxtAegis.authPath}/callback`,
134
+ file: resolver.resolve("./runtime/app/pages/AuthCallback.vue")
135
+ });
136
+ });
137
+ addServerImportsDir(resolver.resolve("./runtime/server/providers"));
138
+ addServerImports([
139
+ // Authentication utilities (from auth.ts)
140
+ { name: "requireAuth", from: resolver.resolve("./runtime/server/utils/auth") },
141
+ { name: "getAuthUser", from: resolver.resolve("./runtime/server/utils/auth") },
142
+ { name: "generateAccessToken", from: resolver.resolve("./runtime/server/utils/auth") },
143
+ { name: "verifyToken", from: resolver.resolve("./runtime/server/utils/auth") },
144
+ { name: "generateAuthTokens", from: resolver.resolve("./runtime/server/utils/auth") },
145
+ // Refresh token management utilities (from refreshToken.ts)
146
+ { name: "revokeRefreshToken", from: resolver.resolve("./runtime/server/utils/refreshToken") },
147
+ { name: "deleteUserRefreshTokens", from: resolver.resolve("./runtime/server/utils/refreshToken") },
148
+ { name: "hashRefreshToken", from: resolver.resolve("./runtime/server/utils/refreshToken") },
149
+ // Cookie utilities (from cookies.ts)
150
+ { name: "setRefreshTokenCookie", from: resolver.resolve("./runtime/server/utils/cookies") },
151
+ { name: "getRefreshTokenFromCookie", from: resolver.resolve("./runtime/server/utils/cookies") },
152
+ // Custom claims utilities (from customClaims.ts)
153
+ { name: "applyCustomClaims", from: resolver.resolve("./runtime/server/utils/customClaims") },
154
+ // Handler utilities (from handler.ts)
155
+ { name: "defineAegisHandler", from: resolver.resolve("./runtime/server/utils/handler") },
156
+ { name: "useAegisHandler", from: resolver.resolve("./runtime/server/utils/handler") }
157
+ ]);
158
+ addServerHandler({
159
+ route: runtimeConfig.public.nuxtAegis.userInfoPath,
160
+ handler: resolver.resolve("./runtime/server/routes/me.get"),
161
+ method: "get"
162
+ });
163
+ addServerHandler({
164
+ route: runtimeConfig.public.nuxtAegis.logoutPath,
165
+ handler: resolver.resolve("./runtime/server/routes/logout.post"),
166
+ method: "post"
167
+ });
168
+ addServerHandler({
169
+ route: `${runtimeConfig.public.nuxtAegis.authPath}/token`,
170
+ handler: resolver.resolve("./runtime/server/routes/token.post"),
171
+ method: "post"
172
+ });
173
+ addServerHandler({
174
+ route: runtimeConfig.public.nuxtAegis.refreshPath,
175
+ handler: resolver.resolve("./runtime/server/routes/refresh.post"),
176
+ method: "post"
177
+ });
178
+ if (options.impersonation?.enabled) {
179
+ addServerHandler({
180
+ route: `${runtimeConfig.public.nuxtAegis.authPath}/impersonate`,
181
+ handler: resolver.resolve("./runtime/server/routes/impersonate.post"),
182
+ method: "post"
183
+ });
184
+ addServerHandler({
185
+ route: `${runtimeConfig.public.nuxtAegis.authPath}/unimpersonate`,
186
+ handler: resolver.resolve("./runtime/server/routes/unimpersonate.post"),
187
+ method: "post"
188
+ });
189
+ }
190
+ if (options.providers?.password) {
191
+ const passwordRoutes = [
192
+ { path: "password/register", file: "register.post", method: "post" },
193
+ { path: "password/register-verify", file: "register-verify.get", method: "get" },
194
+ { path: "password/login", file: "login.post", method: "post" },
195
+ { path: "password/login-verify", file: "login-verify.get", method: "get" },
196
+ { path: "password/reset-request", file: "reset-request.post", method: "post" },
197
+ { path: "password/reset-verify", file: "reset-verify.get", method: "get" },
198
+ { path: "password/reset-complete", file: "reset-complete.post", method: "post" },
199
+ { path: "password/change", file: "change.post", method: "post" }
200
+ ];
201
+ for (const route of passwordRoutes) {
202
+ addServerHandler({
203
+ route: `${runtimeConfig.public.nuxtAegis.authPath}/${route.path}`,
204
+ handler: resolver.resolve(`./runtime/server/routes/password/${route.file}`),
205
+ method: route.method
206
+ });
207
+ }
208
+ }
209
+ addServerHandler({
210
+ handler: resolver.resolve("./runtime/server/middleware/auth"),
211
+ middleware: true
212
+ });
213
+ if (options.enableSSR) {
214
+ addServerPlugin(resolver.resolve("./runtime/server/plugins/ssr-auth"));
215
+ addPlugin(resolver.resolve("./runtime/app/plugins/api.server"));
216
+ addPlugin(resolver.resolve("./runtime/app/plugins/ssr-state.server"));
217
+ }
218
+ const logger = useLogger("nuxt-aegis");
219
+ if (options.clientMiddleware?.enabled) {
220
+ const cm = options.clientMiddleware;
221
+ if (cm.global) {
222
+ const userPublicRoutes = cm.publicRoutes || [];
223
+ const redirectRoutes = [cm.redirectTo, cm.loggedOutRedirectTo];
224
+ const allPublicRoutes = [.../* @__PURE__ */ new Set([...userPublicRoutes, ...redirectRoutes])];
225
+ options.clientMiddleware.publicRoutes = allPublicRoutes;
226
+ if (allPublicRoutes.length === 0) {
227
+ throw new Error(
228
+ "[nuxt-aegis] clientMiddleware.global is enabled but no publicRoutes are configured. At minimum, the redirectTo and loggedOutRedirectTo routes will be automatically included."
229
+ );
230
+ }
231
+ } else {
232
+ const userPublicRoutes = cm.publicRoutes || [];
233
+ if (userPublicRoutes.length > 0) {
234
+ logger.warn(
235
+ "[nuxt-aegis] clientMiddleware.publicRoutes is configured but will be ignored because clientMiddleware.global is false. The auth-logged-in middleware will only run on pages where you explicitly add it via definePageMeta({ middleware: ['auth-logged-in'] })."
236
+ );
237
+ }
238
+ }
239
+ addRouteMiddleware({
240
+ name: "auth-logged-in",
241
+ path: resolver.resolve("./runtime/app/middleware/auth-logged-in"),
242
+ global: options.clientMiddleware.global === true
243
+ });
244
+ addRouteMiddleware({
245
+ name: "auth-logged-out",
246
+ path: resolver.resolve("./runtime/app/middleware/auth-logged-out"),
247
+ global: false
248
+ });
249
+ }
250
+ const isProduction = process.env.NODE_ENV === "production";
251
+ if (!isProduction) {
252
+ const mockConfig = options.providers?.mock;
253
+ if (mockConfig) {
254
+ addServerHandler({
255
+ route: `${runtimeConfig.public.nuxtAegis.authPath}/mock/authorize`,
256
+ handler: resolver.resolve("./runtime/server/routes/mock/authorize.get"),
257
+ method: "get"
258
+ });
259
+ addServerHandler({
260
+ route: `${runtimeConfig.public.nuxtAegis.authPath}/mock/token`,
261
+ handler: resolver.resolve("./runtime/server/routes/mock/token.post"),
262
+ method: "post"
263
+ });
264
+ addServerHandler({
265
+ route: `${runtimeConfig.public.nuxtAegis.authPath}/mock/userinfo`,
266
+ handler: resolver.resolve("./runtime/server/routes/mock/userinfo.get"),
267
+ method: "get"
268
+ });
269
+ }
270
+ }
271
+ if (!nuxt.options.nitro) {
272
+ nuxt.options.nitro = {};
273
+ }
274
+ if (!nuxt.options.nitro.experimental) {
275
+ nuxt.options.nitro.experimental = {};
276
+ }
277
+ nuxt.options.nitro.experimental.tasks = true;
278
+ nuxt.hook("nitro:config", (nitroConfig) => {
279
+ nitroConfig.scanDirs = nitroConfig.scanDirs || [];
280
+ nitroConfig.scanDirs.push(resolver.resolve("./runtime"));
281
+ });
282
+ if (!nuxt.options.nitro.scheduledTasks) {
283
+ nuxt.options.nitro.scheduledTasks = {};
284
+ }
285
+ nuxt.options.nitro.scheduledTasks["0 2 * * *"] = [
286
+ "cleanup:refresh-tokens",
287
+ "cleanup:magic-codes",
288
+ "cleanup:reset-sessions"
289
+ ];
290
+ if (!nuxt.options.nitro.storage) {
291
+ nuxt.options.nitro.storage = {};
292
+ }
293
+ const storageConfig = options.tokenRefresh?.storage || {};
294
+ nuxt.options.nitro.storage.refreshTokenStore = defu(nuxt.options.nitro.storage.refreshTokenStore, {
295
+ driver: storageConfig.driver || "fs",
296
+ base: storageConfig.base || "./.data/refresh-tokens"
297
+ });
298
+ nuxt.options.nitro.storage.authCodeStore = defu(nuxt.options.nitro.storage.authCodeStore, {
299
+ driver: "memory"
300
+ });
301
+ nuxt.options.nitro.storage.magicCodeStore = defu(nuxt.options.nitro.storage.magicCodeStore, {
302
+ driver: "memory"
303
+ });
304
+ nuxt.options.nitro.storage.resetSessionStore = defu(nuxt.options.nitro.storage.resetSessionStore, {
305
+ driver: "memory"
306
+ });
307
+ nuxt.hook("pages:routerOptions", (routerOptions) => {
308
+ routerOptions.files.push({
309
+ path: resolver.resolve("./runtime/app/router.options")
310
+ });
311
+ });
312
+ const typesPath = resolver.resolve("./runtime/types");
313
+ addTemplate({
314
+ filename: "types/nuxt-aegis.d.ts",
315
+ write: true,
316
+ getContents: () => {
317
+ return `import type { NitroAegisAuth, CustomTokenClaims } from ${JSON.stringify(typesPath)}
318
+
319
+ type NuxtAegisRouteRules = {
320
+ /**
321
+ * Authentication requirement for this route
322
+ * - true | 'required' | 'protected': Route requires authentication
323
+ * - false | 'public' | 'skip': Route is public and skips authentication
324
+ * - undefined: Route is not protected (opt-in behavior)
325
+ */
326
+ auth?: NitroAegisAuth
327
+ }
328
+
329
+ declare module 'nitropack/types' {
330
+ interface NitroRouteRules {
331
+ nuxtAegis?: NuxtAegisRouteRules
332
+ }
333
+ interface NitroRouteConfig {
334
+ nuxtAegis?: NuxtAegisRouteRules
335
+ }
336
+ }
337
+
338
+ declare module 'nitropack' {
339
+ interface NitroRouteRules {
340
+ nuxtAegis?: NuxtAegisRouteRules
341
+ }
342
+ interface NitroRouteConfig {
343
+ nuxtAegis?: NuxtAegisRouteRules
344
+ }
345
+ }
346
+
347
+ // Export user-facing types for direct import
348
+ export { type CustomTokenClaims }`;
349
+ }
350
+ });
351
+ }
352
+ });
353
+
354
+ export { module$1 as default };
@@ -0,0 +1,85 @@
1
+ import type { ComputedRef } from 'vue';
2
+ import type { TokenPayload } from '../../types/index.js';
3
+ /**
4
+ * Return type for the useAuth composable
5
+ * @template T - Token payload type extending TokenPayload (defaults to TokenPayload)
6
+ */
7
+ interface UseAuthReturn<T extends TokenPayload = TokenPayload> {
8
+ /** Reactive property indicating whether a user is logged in */
9
+ isLoggedIn: ComputedRef<boolean>;
10
+ /** Reactive property indicating the authentication state is being initialized */
11
+ isLoading: ComputedRef<boolean>;
12
+ /** Reactive property containing the current user's data */
13
+ user: ComputedRef<T | null>;
14
+ /** Error state for authentication operations */
15
+ error: ComputedRef<string | null>;
16
+ /** Reactive property indicating if currently impersonating another user */
17
+ isImpersonating: ComputedRef<boolean>;
18
+ /** Reactive property containing original user data when impersonating */
19
+ originalUser: ComputedRef<{
20
+ originalUserId: string;
21
+ originalUserEmail?: string;
22
+ originalUserName?: string;
23
+ } | null>;
24
+ /** Method to initiate the authentication flow */
25
+ login: (provider?: string, redirectTo?: string) => Promise<void>;
26
+ /** Method to end the user session */
27
+ logout: (redirectTo?: string) => Promise<void>;
28
+ /** Method to refresh the authentication state */
29
+ refresh: () => Promise<void>;
30
+ /** Method to impersonate another user (admin only) */
31
+ impersonate: (targetUserId: string, reason?: string) => Promise<void>;
32
+ /** Method to stop impersonation and restore original session */
33
+ stopImpersonation: () => Promise<void>;
34
+ }
35
+ /**
36
+ * Composable for managing authentication state and actions
37
+ *
38
+ * This composable provides methods for OAuth authentication using a CODE-based flow:
39
+ *
40
+ * Authentication Flow:
41
+ * 1. login() redirects to OAuth provider authentication page
42
+ * 2. Provider redirects back with short-lived authorization CODE (60s)
43
+ * 3. AuthCallback page exchanges CODE for JWT tokens via /auth/token
44
+ * 4. Access token stored in memory (reactive ref, cleared on refresh)
45
+ * 5. Refresh token stored as HttpOnly, Secure cookie
46
+ *
47
+ * Token Storage:
48
+ * - Access token in memory only (NOT sessionStorage)
49
+ * - Automatically cleared on page refresh/window close
50
+ * - Refresh token cookie used to obtain new access token after refresh
51
+ *
52
+ * State Management:
53
+ * - isLoggedIn reactive property (true when user authenticated)
54
+ * - isLoading reactive property (true during state initialization)
55
+ * - user reactive property (null when not authenticated)
56
+ * - State synchronized reactively across all components
57
+ *
58
+ * Methods:
59
+ * - login(provider) - Initiate OAuth flow
60
+ * - logout() - End user session
61
+ * - refresh() - Restore authentication state
62
+ *
63
+ * @template T - Custom token payload type extending TokenPayload
64
+ * @returns {UseAuthReturn<T>} Authentication state and methods
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * // Without custom claims (default)
69
+ * const { user, login, logout } = useAuth()
70
+ *
71
+ * // With custom claims
72
+ * import type { CustomTokenClaims } from '#build/types/nuxt-aegis'
73
+ *
74
+ * type AppTokenPayload = CustomTokenClaims<{
75
+ * role: string
76
+ * permissions: string[]
77
+ * organizationId: string
78
+ * }>
79
+ *
80
+ * const { user, login, logout } = useAuth<AppTokenPayload>()
81
+ * // user.value?.role is now type-safe
82
+ * ```
83
+ */
84
+ export declare function useAuth<T extends TokenPayload = TokenPayload>(): UseAuthReturn<T>;
85
+ export {};