@zephkelly/nuxt-authkit 0.0.1

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 (75) hide show
  1. package/README.md +170 -0
  2. package/dist/module.d.mts +6 -0
  3. package/dist/module.json +9 -0
  4. package/dist/module.mjs +80 -0
  5. package/dist/runtime/composables/useAuthkitToken.d.ts +25 -0
  6. package/dist/runtime/composables/useAuthkitToken.js +31 -0
  7. package/dist/runtime/helpers/request-middleware.d.ts +22 -0
  8. package/dist/runtime/helpers/request-middleware.js +82 -0
  9. package/dist/runtime/index.d.ts +8 -0
  10. package/dist/runtime/index.js +2 -0
  11. package/dist/runtime/plugins/auth-fetch.client.d.ts +13 -0
  12. package/dist/runtime/plugins/auth-fetch.client.js +91 -0
  13. package/dist/runtime/plugins/internal/request-target.d.ts +16 -0
  14. package/dist/runtime/plugins/internal/request-target.js +17 -0
  15. package/dist/runtime/roles/has-role.d.ts +21 -0
  16. package/dist/runtime/roles/has-role.js +51 -0
  17. package/dist/runtime/server/api/_auth/refresh-handler.d.ts +6 -0
  18. package/dist/runtime/server/api/_auth/refresh-handler.js +44 -0
  19. package/dist/runtime/server/api/_auth/refresh.post.d.ts +6 -0
  20. package/dist/runtime/server/api/_auth/refresh.post.js +5 -0
  21. package/dist/runtime/server/tsconfig.json +3 -0
  22. package/dist/runtime/service/index.d.ts +119 -0
  23. package/dist/runtime/service/index.js +170 -0
  24. package/dist/runtime/service/new-index.d.ts +24 -0
  25. package/dist/runtime/service/new-index.js +0 -0
  26. package/dist/runtime/service/types/async-service.d.ts +59 -0
  27. package/dist/runtime/service/types/async-service.js +0 -0
  28. package/dist/runtime/service/types/sync-service.d.ts +28 -0
  29. package/dist/runtime/service/types/sync-service.js +0 -0
  30. package/dist/runtime/service/utils/getJwtAsyncService.d.ts +11 -0
  31. package/dist/runtime/service/utils/getJwtAsyncService.js +16 -0
  32. package/dist/runtime/storage/nitro.d.ts +61 -0
  33. package/dist/runtime/storage/nitro.js +124 -0
  34. package/dist/runtime/storage/types.d.ts +27 -0
  35. package/dist/runtime/storage/types.js +0 -0
  36. package/dist/runtime/strategy/base.d.ts +40 -0
  37. package/dist/runtime/strategy/base.js +88 -0
  38. package/dist/runtime/strategy/jwt/callback.d.ts +60 -0
  39. package/dist/runtime/strategy/jwt/callback.js +0 -0
  40. package/dist/runtime/strategy/jwt/index.d.ts +137 -0
  41. package/dist/runtime/strategy/jwt/index.js +748 -0
  42. package/dist/runtime/strategy/jwt/jwt-crypto.d.ts +122 -0
  43. package/dist/runtime/strategy/jwt/jwt-crypto.js +298 -0
  44. package/dist/runtime/strategy/jwt/types.d.ts +68 -0
  45. package/dist/runtime/strategy/jwt/types.js +0 -0
  46. package/dist/runtime/strategy/types.d.ts +68 -0
  47. package/dist/runtime/strategy/types.js +0 -0
  48. package/dist/runtime/types/2fac.d.ts +32 -0
  49. package/dist/runtime/types/2fac.js +0 -0
  50. package/dist/runtime/types/authkit-types.d.ts +6 -0
  51. package/dist/runtime/types/authkit-types.js +0 -0
  52. package/dist/runtime/types/callbacks.d.ts +133 -0
  53. package/dist/runtime/types/callbacks.js +0 -0
  54. package/dist/runtime/types/cookie.d.ts +47 -0
  55. package/dist/runtime/types/cookie.js +0 -0
  56. package/dist/runtime/types/expand.d.ts +3 -0
  57. package/dist/runtime/types/expand.js +0 -0
  58. package/dist/runtime/types/index.d.ts +52 -0
  59. package/dist/runtime/types/index.js +0 -0
  60. package/dist/runtime/types/module-options.d.ts +33 -0
  61. package/dist/runtime/types/module-options.js +0 -0
  62. package/dist/runtime/types/runtime-config.d.ts +2 -0
  63. package/dist/runtime/types/runtime-config.js +47 -0
  64. package/dist/runtime/types/token.d.ts +42 -0
  65. package/dist/runtime/types/token.js +12 -0
  66. package/dist/runtime/utils/context-helpers.d.ts +4 -0
  67. package/dist/runtime/utils/context-helpers.js +10 -0
  68. package/dist/runtime/utils/get-module-options.d.ts +2 -0
  69. package/dist/runtime/utils/get-module-options.js +18 -0
  70. package/dist/runtime/utils/password.d.ts +23 -0
  71. package/dist/runtime/utils/password.js +18 -0
  72. package/dist/runtime/utils/uuid.d.ts +187 -0
  73. package/dist/runtime/utils/uuid.js +345 -0
  74. package/dist/types.d.mts +7 -0
  75. package/package.json +65 -0
@@ -0,0 +1,44 @@
1
+ import { createError, getHeader } from "h3";
2
+ import { consola } from "consola";
3
+ import { getAuthkit } from "../../../service/utils/getJwtAsyncService.js";
4
+ function assertNotCrossSite(event) {
5
+ const secFetchSite = getHeader(event, "sec-fetch-site");
6
+ if (secFetchSite === "cross-site") {
7
+ throw createError({
8
+ statusCode: 403,
9
+ statusMessage: "Forbidden"
10
+ });
11
+ }
12
+ }
13
+ export async function handleRefreshRequest(event) {
14
+ assertNotCrossSite(event);
15
+ let refreshResult;
16
+ try {
17
+ const auth = getAuthkit();
18
+ refreshResult = await auth.refresh();
19
+ } catch (error) {
20
+ consola.error("[nuxt-authkit] Unexpected error while refreshing token:", error);
21
+ throw createError({
22
+ statusCode: 500,
23
+ statusMessage: "Internal Server Error"
24
+ });
25
+ }
26
+ if (!refreshResult.success) {
27
+ consola.debug("[nuxt-authkit] Refresh rejected:", refreshResult.error);
28
+ throw createError({
29
+ statusCode: 401,
30
+ statusMessage: "Unauthorized",
31
+ data: {
32
+ error: {
33
+ code: refreshResult.error?.code ?? "REFRESH_TOKEN_INVALID",
34
+ recoverable: refreshResult.error?.recoverable ?? false
35
+ }
36
+ }
37
+ });
38
+ }
39
+ return {
40
+ status: "ok",
41
+ message: "Token refreshed",
42
+ data: refreshResult
43
+ };
44
+ }
@@ -0,0 +1,6 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{
2
+ status: string;
3
+ message: string;
4
+ data: import("../../../index.js").AuthResult;
5
+ }>>;
6
+ export default _default;
@@ -0,0 +1,5 @@
1
+ import { eventHandler } from "h3";
2
+ import { handleRefreshRequest } from "./refresh-handler.js";
3
+ export default eventHandler(async (event) => {
4
+ return await handleRefreshRequest(event);
5
+ });
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "../../../.nuxt/tsconfig.server.json",
3
+ }
@@ -0,0 +1,119 @@
1
+ import type { H3Event } from 'h3';
2
+ import type { AuthResult, VerifyAuthResult } from '../types/index.js';
3
+ import type { IAuthStrategy } from '../strategy/types.js';
4
+ import type { AuthkitCredentials } from '#nuxt-authkit';
5
+ import type { IAuthServiceAsync } from './types/async-service.js';
6
+ import type { Expand } from '../types/expand.js';
7
+ /**
8
+ * Singleton Authentication Service
9
+ *
10
+ * Manages authentication using a pluggable strategy pattern.
11
+ * Types are automatically inferred from module augmentation.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * // 1. Define types once:
16
+ * declare module 'nuxt-auth-toolkit' {
17
+ * interface AuthKitTypes {
18
+ * User: MyUser
19
+ * Credentials: MyCredentials
20
+ * }
21
+ * }
22
+ *
23
+ * // 2. Use everywhere without type parameters:
24
+ * const auth = getNuxtAuthkit() // Automatically typed!
25
+ * ```
26
+ */
27
+ export declare class AuthenticationService implements IAuthServiceAsync {
28
+ private static instance;
29
+ private static isInitialized;
30
+ private readonly strategy;
31
+ private constructor();
32
+ /**
33
+ * Initialize the singleton instance
34
+ * Must be called once during app startup
35
+ */
36
+ static init(strategy: IAuthStrategy): AuthenticationService;
37
+ /**
38
+ * Get the singleton instance
39
+ * Types are automatically inferred from module augmentation
40
+ */
41
+ static getInstance(): AuthenticationService;
42
+ /**
43
+ * Check if service is initialized
44
+ */
45
+ static isReady(): boolean;
46
+ /**
47
+ * Reset the singleton (useful for testing)
48
+ */
49
+ static reset(): void;
50
+ /**
51
+ * Get the strategy name
52
+ */
53
+ get strategyName(): string;
54
+ /**
55
+ * Authenticate user with credentials
56
+ */
57
+ authenticate(credentials: AuthkitCredentials, options?: {
58
+ accessExpiresIn?: number;
59
+ refreshExpiresIn?: number;
60
+ }, event?: H3Event): Promise<AuthResult>;
61
+ /**
62
+ * Verify a token
63
+ */
64
+ verify(event?: H3Event, options?: any): Promise<VerifyAuthResult>;
65
+ /**
66
+ * Verify a bare access token, with no request context.
67
+ *
68
+ * Synchronous by design: this is signature + claim validation only, and its
69
+ * callers (WebSocket upgrade handlers, workers) are often outside a request.
70
+ */
71
+ verifyToken(token: string): VerifyAuthResult;
72
+ /**
73
+ * Issue tokens for an already-identified user, bypassing credentials.
74
+ */
75
+ issueTokens(userId: string, options?: {
76
+ roles?: string[];
77
+ claims?: Record<string, unknown>;
78
+ accessExpiresIn?: number;
79
+ refreshExpiresIn?: number;
80
+ }, event?: H3Event): Promise<AuthResult>;
81
+ /**
82
+ * Refresh tokens
83
+ */
84
+ refresh(event?: H3Event, options?: any): Promise<AuthResult>;
85
+ /**
86
+ * Revoke/invalidate tokens
87
+ */
88
+ revoke(event?: H3Event): Promise<void>;
89
+ /**
90
+ * Revoke/invalidate tokens during logout (server initiated) - e.g. Nitro scheduled task
91
+ *
92
+ * Throws if the active strategy cannot perform server-side revocation, rather
93
+ * than resolving successfully having done nothing — an operator running an
94
+ * incident force-logout has to be able to trust the answer.
95
+ */
96
+ revokeServer(options: any, event?: H3Event): Promise<void>;
97
+ }
98
+ /**
99
+ * Factory function to create and initialize the singleton
100
+ * Types are automatically inferred from module augmentation
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * // 1. Define your types once (in types/auth.ts):
105
+ * declare module 'nuxt-auth-toolkit' {
106
+ * interface AuthKitTypes {
107
+ * User: { id: number; email: string; name: string }
108
+ * Credentials: { username: string; password: string }
109
+ * }
110
+ * }
111
+ *
112
+ * // 2. Initialize (in server/plugins/auth.ts):
113
+ * export default defineNitroPlugin((nitroApp) => {
114
+ * const strategy = new JwtStrategy({ ... }, callbacks)
115
+ * createAuthenticationService(nitroApp, strategy) // Types inferred!
116
+ * })
117
+ * ```
118
+ */
119
+ export declare function createNuxtAuthkit<TCredentials = AuthkitCredentials>(strategy: IAuthStrategy): Expand<IAuthServiceAsync<TCredentials>>;
@@ -0,0 +1,170 @@
1
+ import { useEvent } from "nitropack/runtime/internal/context";
2
+ import { consola } from "consola";
3
+ export class AuthenticationService {
4
+ static instance = null;
5
+ static isInitialized = false;
6
+ strategy;
7
+ constructor(strategy) {
8
+ this.strategy = strategy;
9
+ }
10
+ /**
11
+ * Initialize the singleton instance
12
+ * Must be called once during app startup
13
+ */
14
+ static init(strategy) {
15
+ if (this.isInitialized && this.instance) {
16
+ return this.instance;
17
+ }
18
+ this.instance = new AuthenticationService(
19
+ strategy
20
+ );
21
+ this.isInitialized = true;
22
+ consola.log({
23
+ message: `Using strategy: \x1B[32m${strategy.name} \x1B`,
24
+ tag: "\x1B[32m nuxt-authkit \x1B"
25
+ });
26
+ return this.instance;
27
+ }
28
+ /**
29
+ * Get the singleton instance
30
+ * Types are automatically inferred from module augmentation
31
+ */
32
+ static getInstance() {
33
+ if (!this.instance || !this.isInitialized) {
34
+ throw new Error(
35
+ "[nuxt-authkit] not initialized. Call createNuxtAuthkit() first in your Nitro plugin."
36
+ );
37
+ }
38
+ return this.instance;
39
+ }
40
+ /**
41
+ * Check if service is initialized
42
+ */
43
+ static isReady() {
44
+ return this.isInitialized && this.instance !== null;
45
+ }
46
+ /**
47
+ * Reset the singleton (useful for testing)
48
+ */
49
+ static reset() {
50
+ this.instance = null;
51
+ this.isInitialized = false;
52
+ }
53
+ /**
54
+ * Get the strategy name
55
+ */
56
+ get strategyName() {
57
+ return this.strategy.name;
58
+ }
59
+ // ========== Authentication Methods ==========
60
+ /**
61
+ * Authenticate user with credentials
62
+ */
63
+ async authenticate(credentials, options, event) {
64
+ const currentEvent = event ? event : typeof useEvent === "function" ? useEvent() : void 0;
65
+ try {
66
+ return await this.strategy.authenticate(credentials, currentEvent, options);
67
+ } catch (error) {
68
+ console.error("[nuxt-authkit] Authentication error:", error);
69
+ throw error;
70
+ }
71
+ }
72
+ /**
73
+ * Verify a token
74
+ */
75
+ async verify(event, options) {
76
+ const currentEvent = event ? event : typeof useEvent === "function" ? useEvent() : void 0;
77
+ try {
78
+ return await this.strategy.verify(currentEvent, options);
79
+ } catch (error) {
80
+ console.error("[nuxt-authkit] Token verification error:", error);
81
+ throw error;
82
+ }
83
+ }
84
+ /**
85
+ * Verify a bare access token, with no request context.
86
+ *
87
+ * Synchronous by design: this is signature + claim validation only, and its
88
+ * callers (WebSocket upgrade handlers, workers) are often outside a request.
89
+ */
90
+ verifyToken(token) {
91
+ if (typeof this.strategy.verifyToken !== "function") {
92
+ throw new TypeError(
93
+ `[nuxt-authkit] The "${this.strategy.name}" strategy does not support context-free token verification.`
94
+ );
95
+ }
96
+ return this.strategy.verifyToken(token);
97
+ }
98
+ /**
99
+ * Issue tokens for an already-identified user, bypassing credentials.
100
+ */
101
+ async issueTokens(userId, options, event) {
102
+ if (typeof this.strategy.issueTokens !== "function") {
103
+ throw new TypeError(
104
+ `[nuxt-authkit] The "${this.strategy.name}" strategy does not support issuing tokens without credentials.`
105
+ );
106
+ }
107
+ const currentEvent = event ? event : typeof useEvent === "function" ? useEvent() : void 0;
108
+ try {
109
+ return await this.strategy.issueTokens(userId, currentEvent, options);
110
+ } catch (error) {
111
+ console.error("[nuxt-authkit] Token issuance error:", error);
112
+ throw error;
113
+ }
114
+ }
115
+ /**
116
+ * Refresh tokens
117
+ */
118
+ async refresh(event, options) {
119
+ const currentEvent = event ? event : typeof useEvent === "function" ? useEvent() : void 0;
120
+ try {
121
+ return await this.strategy.refresh(currentEvent, options);
122
+ } catch (error) {
123
+ console.error("[nuxt-authkit] Token refresh error:", error);
124
+ throw error;
125
+ }
126
+ }
127
+ /**
128
+ * Revoke/invalidate tokens
129
+ */
130
+ async revoke(event) {
131
+ const currentEvent = event ? event : typeof useEvent === "function" ? useEvent() : void 0;
132
+ try {
133
+ await this.strategy.revoke(currentEvent);
134
+ } catch (error) {
135
+ console.error("[nuxt-authkit] Token revocation error:", error);
136
+ throw error;
137
+ }
138
+ }
139
+ /**
140
+ * Revoke/invalidate tokens during logout (server initiated) - e.g. Nitro scheduled task
141
+ *
142
+ * Throws if the active strategy cannot perform server-side revocation, rather
143
+ * than resolving successfully having done nothing — an operator running an
144
+ * incident force-logout has to be able to trust the answer.
145
+ */
146
+ async revokeServer(options, event) {
147
+ if (typeof this.strategy.revokeServer !== "function") {
148
+ throw new TypeError(
149
+ `[nuxt-authkit] The "${this.strategy.name}" strategy does not support server-initiated revocation.`
150
+ );
151
+ }
152
+ let currentEvent = event;
153
+ if (!currentEvent && typeof useEvent === "function") {
154
+ try {
155
+ currentEvent = useEvent();
156
+ } catch {
157
+ currentEvent = void 0;
158
+ }
159
+ }
160
+ try {
161
+ await this.strategy.revokeServer(options, currentEvent);
162
+ } catch (error) {
163
+ console.error("[nuxt-authkit] Server token revocation error:", error);
164
+ throw error;
165
+ }
166
+ }
167
+ }
168
+ export function createNuxtAuthkit(strategy) {
169
+ return AuthenticationService.init(strategy);
170
+ }
@@ -0,0 +1,24 @@
1
+ import type { H3Event } from "h3";
2
+ import type { AuthResult, VerifyAuthResult } from "../types/index.js";
3
+ import type { Expand } from "../types/expand.js";
4
+ import type { AuthkitCredentials } from './../types/authkit-types.js';
5
+ /**
6
+ * Base interface that all authentication strategies must implement
7
+ */
8
+ export interface IAuthService<TCredentials = AuthkitCredentials> {
9
+ /**
10
+ * Authenticate user with credentials
11
+ * Returns tokens and user data on success
12
+ */
13
+ authenticate(credentials: TCredentials, event?: H3Event): Promise<Expand<AuthResult>>;
14
+ /**
15
+ * Verify a that the current authentication method is valid
16
+ */
17
+ verify(event?: H3Event): Promise<VerifyAuthResult>;
18
+ refresh(event?: H3Event): Promise<AuthResult>;
19
+ /**
20
+ * Revoke/invalidate tokens
21
+ * Used during logout
22
+ */
23
+ revoke(event?: H3Event): Promise<void>;
24
+ }
File without changes
@@ -0,0 +1,59 @@
1
+ import type { AuthResult, VerifyAuthResult } from "../../types/index.js";
2
+ import type { Expand } from "../../types/expand.js";
3
+ import type { AuthkitCredentials } from './../../types/authkit-types.js';
4
+ /**
5
+ * Base interface that auth service must implement when experimental 'asyncContext' is used,
6
+ * meaning event is captured via 'useEvent' internally at each method call. Use in nuxt/nitro
7
+ * context only.
8
+ */
9
+ export interface IAuthServiceAsync<TCredentials = AuthkitCredentials, TServerRevokeOptions = {}, TVerifyOptions = {}, TRefreshOptions = {}> {
10
+ /**
11
+ * Authenticate user with credentials
12
+ * Returns tokens and user data on success
13
+ */
14
+ authenticate(credentials: TCredentials, options?: {
15
+ accessExpiresIn?: number;
16
+ refreshExpiresIn?: number;
17
+ }): Promise<Expand<AuthResult>>;
18
+ /**
19
+ * Verify a that the current authentication method is valid
20
+ */
21
+ verify(options?: Expand<TVerifyOptions>): Promise<VerifyAuthResult>;
22
+ /**
23
+ * Verify a bare access token with no request context — for callers that hold
24
+ * a token but no H3 event (WebSocket peers, background workers, signed asset
25
+ * URLs). Synchronous: no store lookup is involved, only signature and claims.
26
+ *
27
+ * Throws if the active strategy has no context-free token to verify.
28
+ */
29
+ verifyToken(token: string): VerifyAuthResult;
30
+ /**
31
+ * Issue a token pair for `userId` without presenting credentials, for flows
32
+ * where identity is already established (OAuth callback, accepted invite,
33
+ * impersonation, device linking).
34
+ *
35
+ * This authenticates nobody — the caller asserts the subject. Never reach it
36
+ * from a route that has not already proven who the user is.
37
+ */
38
+ issueTokens(userId: string, options?: {
39
+ roles?: string[];
40
+ claims?: Record<string, unknown>;
41
+ accessExpiresIn?: number;
42
+ refreshExpiresIn?: number;
43
+ }): Promise<Expand<AuthResult>>;
44
+ /**
45
+ * Exchange the refresh token for a new access token.
46
+ * The refresh token is rotated unless rotation is disabled.
47
+ */
48
+ refresh(options?: Expand<TRefreshOptions>): Promise<AuthResult>;
49
+ /**
50
+ * Revoke/invalidate tokens
51
+ * Used during logout
52
+ */
53
+ revoke(): Promise<void>;
54
+ /**
55
+ * Server-initiated revocation. Throws if the strategy has no
56
+ * `onRevokeServer` callback configured — it will not silently no-op.
57
+ */
58
+ revokeServer(options: Expand<TServerRevokeOptions>): Promise<void>;
59
+ }
File without changes
@@ -0,0 +1,28 @@
1
+ import type { H3Event } from "h3";
2
+ import type { AuthResult, VerifyAuthResult } from "../../types/index.js";
3
+ import type { Expand } from "../../types/expand.js";
4
+ import type { AuthkitCredentials } from '../../types/authkit-types.js';
5
+ export interface RevokeServerOptions {
6
+ }
7
+ /**
8
+ * Base interface that auth service must implement when experimental 'asyncContext' is used,
9
+ * meaning event is captured via 'useEvent' internally at each method call. Use in nuxt/nitro
10
+ * context only.
11
+ */
12
+ export interface IAuthService<TCredentials = AuthkitCredentials> {
13
+ /**
14
+ * Authenticate user with credentials
15
+ * Returns tokens and user data on success
16
+ */
17
+ authenticate(credentials: TCredentials, event: H3Event): Promise<Expand<AuthResult>>;
18
+ /**
19
+ * Verify a that the current authentication method is valid
20
+ */
21
+ verify(event: H3Event): Promise<VerifyAuthResult>;
22
+ refresh(event: H3Event): Promise<AuthResult>;
23
+ /**
24
+ * Revoke/invalidate tokens during logout (client initiated)
25
+ */
26
+ revoke(event: H3Event): Promise<void>;
27
+ revokeServer(options: Expand<RevokeServerOptions>): Promise<void>;
28
+ }
File without changes
@@ -0,0 +1,11 @@
1
+ import type { IAuthServiceAsync } from '../types/async-service.js';
2
+ import type { AuthkitCredentials } from '../../types/authkit-types.js';
3
+ import type { Expand } from '../../types/expand.js';
4
+ import type { JWTServerRevokeOptions, JWTVerifyOptions, JWTRefreshOptions } from '../../strategy/jwt/types.js';
5
+ /**
6
+ * Alias for useAuthenticationService
7
+ * Provides a more Nuxt-friendly name
8
+ * Types are automatically inferred from module augmentation
9
+ * ```
10
+ */
11
+ export declare function getAuthkit<TCredentials = AuthkitCredentials>(): Expand<IAuthServiceAsync<TCredentials, JWTServerRevokeOptions, JWTVerifyOptions, JWTRefreshOptions>>;
@@ -0,0 +1,16 @@
1
+ import { AuthenticationService } from "../index.js";
2
+ export function getAuthkit() {
3
+ const authService = AuthenticationService.getInstance();
4
+ return {
5
+ authenticate: (credentials, options) => authService.authenticate(credentials, options),
6
+ // `undefined` is passed explicitly for the event slot: the service resolves
7
+ // the ambient event itself, and passing options positionally here used to
8
+ // land them in that slot and break every verify({ accessToken }) call.
9
+ verify: (options) => authService.verify(void 0, options),
10
+ verifyToken: (token) => authService.verifyToken(token),
11
+ issueTokens: (userId, options) => authService.issueTokens(userId, options),
12
+ refresh: (options) => authService.refresh(void 0, options),
13
+ revoke: () => authService.revoke(),
14
+ revokeServer: (options) => authService.revokeServer(options)
15
+ };
16
+ }
@@ -0,0 +1,61 @@
1
+ import type { AuthStorage, StorageOptions, StorageAdapter } from './types.js';
2
+ /**
3
+ * Configuration for Nitro storage
4
+ */
5
+ export interface NitroStorageConfig {
6
+ /**
7
+ * Prefix for all storage keys
8
+ * Useful for namespacing auth data
9
+ * @default 'auth'
10
+ */
11
+ prefix?: string;
12
+ /**
13
+ * Default TTL for items (in seconds)
14
+ * If not provided, items don't expire
15
+ */
16
+ ttl?: number;
17
+ }
18
+ /**
19
+ * AuthStorage implementation using Nitro's storage via dependency injection
20
+ *
21
+ * NOTE: not currently used by `JWTStrategy` — refresh-token persistence is
22
+ * delegated entirely to the `onStoreRefreshToken` / `onGetRefreshToken` /
23
+ * `onRemoveRefreshToken` callbacks. Kept as a general-purpose adapter.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const storage = useStorage('redis')
28
+ * const authStorage = new NitroStorage(storage, {
29
+ * prefix: 'auth',
30
+ * ttl: 3600
31
+ * })
32
+ *
33
+ * // Keys are escaped, so a ':' inside an untrusted id cannot forge a namespace.
34
+ * await authStorage.set(userId, token)
35
+ * const token = await authStorage.get(userId)
36
+ * ```
37
+ */
38
+ export declare class NitroStorage implements AuthStorage {
39
+ private readonly config;
40
+ private readonly storage;
41
+ constructor(storage: StorageAdapter, config?: NitroStorageConfig);
42
+ /**
43
+ * `:` is the namespace separator, so a key containing one could otherwise
44
+ * collide with — or overwrite — another namespace's entry when the key is
45
+ * derived from an untrusted identifier. Escape it (and the escape character)
46
+ * before joining.
47
+ */
48
+ private buildKey;
49
+ get(key: string): Promise<string | null>;
50
+ set(key: string, value: string, options?: StorageOptions): Promise<void>;
51
+ remove(key: string): Promise<void>;
52
+ /**
53
+ * Clear all items with this prefix
54
+ * Note: This only works efficiently with some drivers (filesystem, memory)
55
+ */
56
+ clear(): Promise<void>;
57
+ has(key: string): Promise<boolean>;
58
+ getMany(keys: string[]): Promise<Map<string, string | null>>;
59
+ setMany(entries: Array<[string, string]>, options?: StorageOptions): Promise<void>;
60
+ keys(): Promise<string[]>;
61
+ }
@@ -0,0 +1,124 @@
1
+ export class NitroStorage {
2
+ config;
3
+ storage;
4
+ constructor(storage, config = {}) {
5
+ this.storage = storage;
6
+ this.config = {
7
+ prefix: config.prefix ?? "auth",
8
+ ttl: config.ttl ?? 0
9
+ };
10
+ }
11
+ /**
12
+ * `:` is the namespace separator, so a key containing one could otherwise
13
+ * collide with — or overwrite — another namespace's entry when the key is
14
+ * derived from an untrusted identifier. Escape it (and the escape character)
15
+ * before joining.
16
+ */
17
+ buildKey(key) {
18
+ const escaped = key.replace(/\\/g, "\\\\").replace(/:/g, "\\:");
19
+ return this.config.prefix ? `${this.config.prefix}:${escaped}` : escaped;
20
+ }
21
+ async get(key) {
22
+ const fullKey = this.buildKey(key);
23
+ try {
24
+ const value = await this.storage.getItem(fullKey);
25
+ if (!value) {
26
+ return null;
27
+ }
28
+ if (typeof value === "object" && "data" in value && "expiresAt" in value) {
29
+ const wrapped = value;
30
+ if (Date.now() > wrapped.expiresAt) {
31
+ await this.storage.removeItem(fullKey);
32
+ return null;
33
+ }
34
+ return wrapped.data;
35
+ }
36
+ return typeof value === "string" ? value : JSON.stringify(value);
37
+ } catch (error) {
38
+ console.error(
39
+ `[NitroStorage] Error getting key "${fullKey}":`,
40
+ error
41
+ );
42
+ return null;
43
+ }
44
+ }
45
+ async set(key, value, options) {
46
+ const fullKey = this.buildKey(key);
47
+ try {
48
+ const ttl = options?.maxAge ?? this.config.ttl;
49
+ if (ttl > 0) {
50
+ const expiresAt = Date.now() + ttl * 1e3;
51
+ const data = {
52
+ data: value,
53
+ expiresAt
54
+ };
55
+ await this.storage.setItem(fullKey, data);
56
+ } else {
57
+ await this.storage.setItem(fullKey, value);
58
+ }
59
+ } catch (error) {
60
+ console.error(
61
+ `[NitroStorage] Error setting key "${fullKey}":`,
62
+ error
63
+ );
64
+ throw error;
65
+ }
66
+ }
67
+ async remove(key) {
68
+ const fullKey = this.buildKey(key);
69
+ try {
70
+ await this.storage.removeItem(fullKey);
71
+ } catch (error) {
72
+ console.error(
73
+ `[NitroStorage] Error removing key "${fullKey}":`,
74
+ error
75
+ );
76
+ throw error;
77
+ }
78
+ }
79
+ /**
80
+ * Clear all items with this prefix
81
+ * Note: This only works efficiently with some drivers (filesystem, memory)
82
+ */
83
+ async clear() {
84
+ try {
85
+ const keys = await this.storage.getKeys(`${this.config.prefix}:`);
86
+ await Promise.all(keys.map((key) => this.storage.removeItem(key)));
87
+ } catch (error) {
88
+ console.error("[NitroStorage] Error clearing storage:", error);
89
+ throw error;
90
+ }
91
+ }
92
+ async has(key) {
93
+ const value = await this.get(key);
94
+ return value !== null;
95
+ }
96
+ async getMany(keys) {
97
+ const results = /* @__PURE__ */ new Map();
98
+ await Promise.all(
99
+ keys.map(async (key) => {
100
+ const value = await this.get(key);
101
+ results.set(key, value);
102
+ })
103
+ );
104
+ return results;
105
+ }
106
+ async setMany(entries, options) {
107
+ await Promise.all(
108
+ entries.map(([key, value]) => this.set(key, value, options))
109
+ );
110
+ }
111
+ async keys() {
112
+ try {
113
+ const allKeys = await this.storage.getKeys(
114
+ `${this.config.prefix}:`
115
+ );
116
+ return allKeys.map(
117
+ (key) => key.startsWith(this.config.prefix + ":") ? key.slice(this.config.prefix.length + 1) : key
118
+ );
119
+ } catch (error) {
120
+ console.error("[NitroStorage] Error getting keys:", error);
121
+ return [];
122
+ }
123
+ }
124
+ }