@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.
- package/README.md +170 -0
- package/dist/module.d.mts +6 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +80 -0
- package/dist/runtime/composables/useAuthkitToken.d.ts +25 -0
- package/dist/runtime/composables/useAuthkitToken.js +31 -0
- package/dist/runtime/helpers/request-middleware.d.ts +22 -0
- package/dist/runtime/helpers/request-middleware.js +82 -0
- package/dist/runtime/index.d.ts +8 -0
- package/dist/runtime/index.js +2 -0
- package/dist/runtime/plugins/auth-fetch.client.d.ts +13 -0
- package/dist/runtime/plugins/auth-fetch.client.js +91 -0
- package/dist/runtime/plugins/internal/request-target.d.ts +16 -0
- package/dist/runtime/plugins/internal/request-target.js +17 -0
- package/dist/runtime/roles/has-role.d.ts +21 -0
- package/dist/runtime/roles/has-role.js +51 -0
- package/dist/runtime/server/api/_auth/refresh-handler.d.ts +6 -0
- package/dist/runtime/server/api/_auth/refresh-handler.js +44 -0
- package/dist/runtime/server/api/_auth/refresh.post.d.ts +6 -0
- package/dist/runtime/server/api/_auth/refresh.post.js +5 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/runtime/service/index.d.ts +119 -0
- package/dist/runtime/service/index.js +170 -0
- package/dist/runtime/service/new-index.d.ts +24 -0
- package/dist/runtime/service/new-index.js +0 -0
- package/dist/runtime/service/types/async-service.d.ts +59 -0
- package/dist/runtime/service/types/async-service.js +0 -0
- package/dist/runtime/service/types/sync-service.d.ts +28 -0
- package/dist/runtime/service/types/sync-service.js +0 -0
- package/dist/runtime/service/utils/getJwtAsyncService.d.ts +11 -0
- package/dist/runtime/service/utils/getJwtAsyncService.js +16 -0
- package/dist/runtime/storage/nitro.d.ts +61 -0
- package/dist/runtime/storage/nitro.js +124 -0
- package/dist/runtime/storage/types.d.ts +27 -0
- package/dist/runtime/storage/types.js +0 -0
- package/dist/runtime/strategy/base.d.ts +40 -0
- package/dist/runtime/strategy/base.js +88 -0
- package/dist/runtime/strategy/jwt/callback.d.ts +60 -0
- package/dist/runtime/strategy/jwt/callback.js +0 -0
- package/dist/runtime/strategy/jwt/index.d.ts +137 -0
- package/dist/runtime/strategy/jwt/index.js +748 -0
- package/dist/runtime/strategy/jwt/jwt-crypto.d.ts +122 -0
- package/dist/runtime/strategy/jwt/jwt-crypto.js +298 -0
- package/dist/runtime/strategy/jwt/types.d.ts +68 -0
- package/dist/runtime/strategy/jwt/types.js +0 -0
- package/dist/runtime/strategy/types.d.ts +68 -0
- package/dist/runtime/strategy/types.js +0 -0
- package/dist/runtime/types/2fac.d.ts +32 -0
- package/dist/runtime/types/2fac.js +0 -0
- package/dist/runtime/types/authkit-types.d.ts +6 -0
- package/dist/runtime/types/authkit-types.js +0 -0
- package/dist/runtime/types/callbacks.d.ts +133 -0
- package/dist/runtime/types/callbacks.js +0 -0
- package/dist/runtime/types/cookie.d.ts +47 -0
- package/dist/runtime/types/cookie.js +0 -0
- package/dist/runtime/types/expand.d.ts +3 -0
- package/dist/runtime/types/expand.js +0 -0
- package/dist/runtime/types/index.d.ts +52 -0
- package/dist/runtime/types/index.js +0 -0
- package/dist/runtime/types/module-options.d.ts +33 -0
- package/dist/runtime/types/module-options.js +0 -0
- package/dist/runtime/types/runtime-config.d.ts +2 -0
- package/dist/runtime/types/runtime-config.js +47 -0
- package/dist/runtime/types/token.d.ts +42 -0
- package/dist/runtime/types/token.js +12 -0
- package/dist/runtime/utils/context-helpers.d.ts +4 -0
- package/dist/runtime/utils/context-helpers.js +10 -0
- package/dist/runtime/utils/get-module-options.d.ts +2 -0
- package/dist/runtime/utils/get-module-options.js +18 -0
- package/dist/runtime/utils/password.d.ts +23 -0
- package/dist/runtime/utils/password.js +18 -0
- package/dist/runtime/utils/uuid.d.ts +187 -0
- package/dist/runtime/utils/uuid.js +345 -0
- package/dist/types.d.mts +7 -0
- package/package.json +65 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import type { H3Event } from 'h3';
|
|
2
|
+
import type { AuthErrorCode } from '.';
|
|
3
|
+
import type { TokenSet } from './token.js';
|
|
4
|
+
import type { AuthkitCredentials, AuthkitUser } from './../types/authkit-types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Result of an `onGetRefreshToken` lookup.
|
|
7
|
+
*
|
|
8
|
+
* Returning a plain string (the stored token) or `null` is still supported and
|
|
9
|
+
* behaves exactly as before: the library compares it against the presented
|
|
10
|
+
* token in constant time. Returning this object instead lets the store answer
|
|
11
|
+
* the questions only it can answer — was this token *reused* after rotation,
|
|
12
|
+
* and what are the user's roles/claims *right now*.
|
|
13
|
+
*/
|
|
14
|
+
export interface RefreshTokenLookup {
|
|
15
|
+
/** Whether the presented refresh token is currently valid. */
|
|
16
|
+
valid: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* The token was recognised but has already been rotated away — a replay of
|
|
19
|
+
* a superseded token. Signals theft: the library will call
|
|
20
|
+
* `onRevokeTokenFamily` for the token's family.
|
|
21
|
+
*/
|
|
22
|
+
reused?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* The token was superseded moments ago by a refresh that is still in flight
|
|
25
|
+
* (two tabs refreshing at once), rather than replayed by an attacker.
|
|
26
|
+
*
|
|
27
|
+
* Distinguishing this from `reused` matters: the library leaves the refresh
|
|
28
|
+
* cookie alone — the winning request has already set a fresh one — and
|
|
29
|
+
* returns a *recoverable* `REFRESH_TOKEN_RACE` so the client can retry with
|
|
30
|
+
* the new cookie instead of being logged out. Treating a benign race as
|
|
31
|
+
* theft would revoke the whole family and end the session.
|
|
32
|
+
*
|
|
33
|
+
* Your store decides the window: typically "this token was rotated away less
|
|
34
|
+
* than ~10s ago".
|
|
35
|
+
*/
|
|
36
|
+
gracePeriodRace?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Authoritative roles for this user, read fresh from your store. Embedded
|
|
39
|
+
* in the newly-minted access token. Without this (or `onGetRoles`) a
|
|
40
|
+
* refresh cannot reflect a role change or a ban.
|
|
41
|
+
*/
|
|
42
|
+
roles?: string[];
|
|
43
|
+
/** Authoritative custom claims for this user, embedded in the new access token. */
|
|
44
|
+
claims?: Record<string, unknown>;
|
|
45
|
+
/**
|
|
46
|
+
* Lifetime, in seconds, for the *rotated* refresh token.
|
|
47
|
+
*
|
|
48
|
+
* Without this, rotation resets the refresh token to the configured
|
|
49
|
+
* `tokens.refresh.expiresIn`. An app that issues per-user refresh lifetimes
|
|
50
|
+
* at login (say, long-lived for a mobile user, short for staff) would
|
|
51
|
+
* otherwise see them silently collapse to the global default on the first
|
|
52
|
+
* refresh. Return the same value your login path used.
|
|
53
|
+
*/
|
|
54
|
+
refreshExpiresIn?: number;
|
|
55
|
+
}
|
|
56
|
+
export type RefreshTokenLookupResult = string | null | RefreshTokenLookup;
|
|
57
|
+
/**
|
|
58
|
+
* Callbacks that developers implement for custom logic
|
|
59
|
+
*/
|
|
60
|
+
export interface AuthCallbacksGeneral {
|
|
61
|
+
/**
|
|
62
|
+
* Verify user credentials
|
|
63
|
+
* Called during initial authentication
|
|
64
|
+
*/
|
|
65
|
+
onAuthenticate(credentials: AuthkitCredentials, event: H3Event): Promise<string | {
|
|
66
|
+
id: string;
|
|
67
|
+
roles?: string[];
|
|
68
|
+
user?: AuthkitUser;
|
|
69
|
+
claims?: Record<string, unknown>;
|
|
70
|
+
} | null>;
|
|
71
|
+
/**
|
|
72
|
+
* Called after successful authentication
|
|
73
|
+
* Good for logging, analytics, etc.
|
|
74
|
+
*/
|
|
75
|
+
onAuthenticated?(tokens: TokenSet, event: H3Event): Promise<void> | void;
|
|
76
|
+
/**
|
|
77
|
+
* Called when authentication fails
|
|
78
|
+
*/
|
|
79
|
+
onAuthenticationFailed?(reason: AuthErrorCode, event: H3Event): Promise<void> | void;
|
|
80
|
+
/**
|
|
81
|
+
* Called when tokens are refreshed
|
|
82
|
+
*/
|
|
83
|
+
onTokenRefreshed?(tokens: TokenSet, event: H3Event): Promise<void> | void;
|
|
84
|
+
/**
|
|
85
|
+
* Store refresh token securely.
|
|
86
|
+
*
|
|
87
|
+
* Called on authentication and on every rotation. Storing a hash of the
|
|
88
|
+
* token rather than the token itself is strongly recommended.
|
|
89
|
+
*/
|
|
90
|
+
onStoreRefreshToken(refreshToken: string, identifier: string, event: H3Event): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Look up a presented refresh token in your store.
|
|
93
|
+
*
|
|
94
|
+
* @returns the stored token string (legacy), `null` if unknown, or a
|
|
95
|
+
* {@link RefreshTokenLookup} for reuse detection and fresh roles/claims.
|
|
96
|
+
*/
|
|
97
|
+
onGetRefreshToken(refreshToken: string, identifier: string, event: H3Event): Promise<RefreshTokenLookupResult>;
|
|
98
|
+
/**
|
|
99
|
+
* Delete a refresh token from your store.
|
|
100
|
+
*
|
|
101
|
+
* Called on logout (`revoke()`) and on every rotation, for the token being
|
|
102
|
+
* superseded. Without this callback a session cannot be terminated
|
|
103
|
+
* server-side: the refresh token stays redeemable until it expires on its
|
|
104
|
+
* own. The library logs a one-time warning at startup if it is missing.
|
|
105
|
+
*/
|
|
106
|
+
onRemoveRefreshToken?(refreshToken: string, identifier: string, event: H3Event): Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* Re-read this user's authoritative roles, called during `refresh()`.
|
|
109
|
+
*
|
|
110
|
+
* This is the hook that makes bans and role changes take effect on the next
|
|
111
|
+
* refresh instead of on the next login. If neither this nor a
|
|
112
|
+
* {@link RefreshTokenLookup} `roles` value is supplied, roles are carried
|
|
113
|
+
* forward from the presented refresh token.
|
|
114
|
+
*/
|
|
115
|
+
onGetRoles?(userId: string, event: H3Event): Promise<string[] | undefined> | string[] | undefined;
|
|
116
|
+
/**
|
|
117
|
+
* A refresh token was replayed after it had already been rotated away.
|
|
118
|
+
* The standard theft signal: revoke every token in `family`.
|
|
119
|
+
*/
|
|
120
|
+
onRevokeTokenFamily?(family: string, userId: string, event: H3Event): Promise<void>;
|
|
121
|
+
/**
|
|
122
|
+
* Server-initiated revocation (e.g. an admin force-logout or a scheduled
|
|
123
|
+
* task). `revokeServer()` throws if this is not implemented, rather than
|
|
124
|
+
* silently reporting success.
|
|
125
|
+
*/
|
|
126
|
+
onRevokeServer?(options: unknown, event?: H3Event): Promise<void>;
|
|
127
|
+
/**
|
|
128
|
+
* Called when user logs out
|
|
129
|
+
*/
|
|
130
|
+
onLogout?(userId: string, event: H3Event): Promise<void> | void;
|
|
131
|
+
}
|
|
132
|
+
export interface AuthCallbacks extends AuthCallbacksGeneral {
|
|
133
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for the refresh-token cookie.
|
|
3
|
+
*
|
|
4
|
+
* The `@default` values below are the ones actually shipped in
|
|
5
|
+
* `DEFAULT_RUNTIME_CONFIG` — keep them in step with it. Overrides are deep-merged
|
|
6
|
+
* (defu), so setting one key does not drop the others.
|
|
7
|
+
*/
|
|
8
|
+
export interface NuxtAuthkitCookieOptions {
|
|
9
|
+
/**
|
|
10
|
+
* Cookie domain
|
|
11
|
+
* @default undefined
|
|
12
|
+
*/
|
|
13
|
+
domain?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Whether the cookie is only sent over HTTPS.
|
|
16
|
+
* @default true
|
|
17
|
+
*/
|
|
18
|
+
secure?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* SameSite attribute for the cookie.
|
|
21
|
+
*
|
|
22
|
+
* Relaxing this to 'lax' or 'none' is the app's call, but it is what stands
|
|
23
|
+
* between the refresh endpoint and cross-site invocation.
|
|
24
|
+
* @default 'strict'
|
|
25
|
+
*/
|
|
26
|
+
sameSite?: 'lax' | 'strict' | 'none';
|
|
27
|
+
/**
|
|
28
|
+
* Max age of the cookie in seconds
|
|
29
|
+
* @default 604800 (7 days)
|
|
30
|
+
*/
|
|
31
|
+
maxAge?: number;
|
|
32
|
+
/**
|
|
33
|
+
* Name of the cookie
|
|
34
|
+
* @default 'refreshToken'
|
|
35
|
+
*/
|
|
36
|
+
name?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Keep the cookie unreadable from JavaScript.
|
|
39
|
+
*
|
|
40
|
+
* Forced to `true` when the cookie is written — the refresh token is a
|
|
41
|
+
* long-lived credential and must stay out of reach of XSS. This option cannot
|
|
42
|
+
* be used to turn it off.
|
|
43
|
+
*
|
|
44
|
+
* @default true
|
|
45
|
+
*/
|
|
46
|
+
httpOnly?: boolean;
|
|
47
|
+
}
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { H3Event } from 'h3';
|
|
2
|
+
import type { TokenSet, TokenPayload } from './token.js';
|
|
3
|
+
import type { VerificationType, TwoFactorChallenge } from './2fac.js';
|
|
4
|
+
/**
|
|
5
|
+
* Context passed through authentication operations
|
|
6
|
+
* Provides access to request/response and environment info
|
|
7
|
+
*/
|
|
8
|
+
export interface AuthContext {
|
|
9
|
+
/** H3 event (server-side only) */
|
|
10
|
+
event: H3Event;
|
|
11
|
+
/** Client info for logging/security */
|
|
12
|
+
client?: {
|
|
13
|
+
ip?: string;
|
|
14
|
+
userAgent?: string;
|
|
15
|
+
deviceId?: string;
|
|
16
|
+
};
|
|
17
|
+
/** Additional metadata */
|
|
18
|
+
metadata?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
export interface AuthResult {
|
|
21
|
+
/** Whether authentication was successful */
|
|
22
|
+
success: boolean;
|
|
23
|
+
/** Authentication tokens (if successful) */
|
|
24
|
+
tokens?: TokenSet;
|
|
25
|
+
/** Requires additional step (2FA, email verification, etc.) */
|
|
26
|
+
requiresVerification?: boolean;
|
|
27
|
+
/** Type of verification required */
|
|
28
|
+
verificationType?: VerificationType;
|
|
29
|
+
/** Temporary token for completing verification */
|
|
30
|
+
verificationToken?: string;
|
|
31
|
+
/** Challenge data for verification */
|
|
32
|
+
challenge?: TwoFactorChallenge;
|
|
33
|
+
error?: AuthError;
|
|
34
|
+
metadata?: Record<string, unknown>;
|
|
35
|
+
}
|
|
36
|
+
export interface VerifyAuthResult {
|
|
37
|
+
valid: boolean;
|
|
38
|
+
payload?: TokenPayload;
|
|
39
|
+
user?: unknown;
|
|
40
|
+
error?: AuthError;
|
|
41
|
+
/** Token is valid but expired */
|
|
42
|
+
expired?: boolean;
|
|
43
|
+
/** Token needs refresh soon */
|
|
44
|
+
shouldRefresh?: boolean;
|
|
45
|
+
}
|
|
46
|
+
export type AuthErrorCode = 'INVALID_CREDENTIALS' | 'TOKEN_EXPIRED' | 'TOKEN_INVALID' | 'TOKEN_REVOKED' | 'REFRESH_TOKEN_INVALID' | 'REFRESH_TOKEN_EXPIRED' | 'REFRESH_TOKEN_RACE' | 'TWO_FACTOR_REQUIRED' | 'TWO_FACTOR_INVALID' | 'TWO_FACTOR_EXPIRED' | 'USER_NOT_FOUND' | 'USER_DISABLED' | 'RATE_LIMIT_EXCEEDED' | 'SESSION_EXPIRED' | 'INVALID_GRANT' | 'NETWORK_ERROR' | 'EVENT_UNAVAILABLE' | 'UNKNOWN_ERROR';
|
|
47
|
+
export interface AuthError {
|
|
48
|
+
code: AuthErrorCode;
|
|
49
|
+
message: string;
|
|
50
|
+
details?: unknown;
|
|
51
|
+
recoverable?: boolean;
|
|
52
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { JwtStrategyConfig } from '../strategy/jwt/types.js';
|
|
2
|
+
import type { ScryptConfig } from '@adonisjs/hash/types';
|
|
3
|
+
export interface ModuleOptions {
|
|
4
|
+
/**
|
|
5
|
+
* List of authentication strategies to enable
|
|
6
|
+
* This determines which parameters are available in revokeServer()
|
|
7
|
+
*/
|
|
8
|
+
strategies: Array<'jwt'>;
|
|
9
|
+
strategy: JwtStrategyConfig;
|
|
10
|
+
/**
|
|
11
|
+
* scrypt cost parameters for `hashPassword` / `verifyPassword`.
|
|
12
|
+
* Defaults are in `DEFAULT_RUNTIME_CONFIG`.
|
|
13
|
+
*/
|
|
14
|
+
scrypt?: ScryptConfig;
|
|
15
|
+
/**
|
|
16
|
+
* Register the bundled client fetch plugin, which attaches the access token
|
|
17
|
+
* to same-origin requests and transparently refreshes on 401.
|
|
18
|
+
*
|
|
19
|
+
* The plugin assigns `globalThis.$fetch`. An app that already owns its own
|
|
20
|
+
* `$fetch` wrapper must set this to `false`, or the two will fight over the
|
|
21
|
+
* same global and the last one registered wins.
|
|
22
|
+
*
|
|
23
|
+
* @default true
|
|
24
|
+
*/
|
|
25
|
+
clientPlugin?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface NuxtAuthkitRuntimeConfig {
|
|
28
|
+
nuxtAuthkit: {
|
|
29
|
+
strategy: JwtStrategyConfig;
|
|
30
|
+
strategies?: Array<'jwt'>;
|
|
31
|
+
scrypt?: ScryptConfig;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export const DEFAULT_RUNTIME_CONFIG = {
|
|
2
|
+
nuxtAuthkit: {
|
|
3
|
+
strategy: {
|
|
4
|
+
name: "jwt",
|
|
5
|
+
tokens: {
|
|
6
|
+
access: {
|
|
7
|
+
expiresIn: 900
|
|
8
|
+
},
|
|
9
|
+
refresh: {
|
|
10
|
+
expiresIn: 604800,
|
|
11
|
+
storageKey: "auth.refresh_token",
|
|
12
|
+
rotate: true,
|
|
13
|
+
cookie: {
|
|
14
|
+
name: "refreshToken",
|
|
15
|
+
secure: true,
|
|
16
|
+
sameSite: "strict",
|
|
17
|
+
httpOnly: true,
|
|
18
|
+
maxAge: 604800
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
autoRefresh: {
|
|
23
|
+
enabled: true,
|
|
24
|
+
beforeExpiry: 60
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
/**
|
|
28
|
+
* scrypt cost parameters. These match the @adonisjs/hash driver defaults, and
|
|
29
|
+
* are stated explicitly because they were previously dropped on the way into
|
|
30
|
+
* runtimeConfig — a custom `scrypt` option had no effect at all.
|
|
31
|
+
*
|
|
32
|
+
* OWASP's current guidance is stronger than this (N=2^17 at p=1, or N=2^14 at
|
|
33
|
+
* p≥5). Raising `cost` is safe to do at any time: the parameters are embedded
|
|
34
|
+
* in each stored PHC hash string, so hashes made under the old settings keep
|
|
35
|
+
* verifying. It costs CPU and memory per login — measure before raising it on
|
|
36
|
+
* a busy API.
|
|
37
|
+
*/
|
|
38
|
+
scrypt: {
|
|
39
|
+
cost: 16384,
|
|
40
|
+
blockSize: 8,
|
|
41
|
+
parallelization: 1,
|
|
42
|
+
saltSize: 16,
|
|
43
|
+
keyLength: 64,
|
|
44
|
+
maxMemory: 33554432
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export interface TokenSet {
|
|
2
|
+
accessToken: string;
|
|
3
|
+
refreshToken?: string;
|
|
4
|
+
idToken?: string;
|
|
5
|
+
expiresAt?: number;
|
|
6
|
+
expiresIn?: number;
|
|
7
|
+
tokenType?: string;
|
|
8
|
+
scope?: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface TokenMetadata {
|
|
11
|
+
issuedAt: number;
|
|
12
|
+
expiresAt: number;
|
|
13
|
+
userId?: string;
|
|
14
|
+
sessionId?: string;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Distinguishes an access token from a refresh token.
|
|
19
|
+
*
|
|
20
|
+
* Both token kinds are signed with the same key, so without this claim a
|
|
21
|
+
* refresh token is structurally replayable as a Bearer access token.
|
|
22
|
+
*/
|
|
23
|
+
export type TokenUse = 'access' | 'refresh';
|
|
24
|
+
/**
|
|
25
|
+
* Claim names the library computes itself. A value supplied through
|
|
26
|
+
* `jwt.claims` (or an `onAuthenticate` / `onGetRoles` claims object) can never
|
|
27
|
+
* override one of these — see `assertNoReservedClaims`.
|
|
28
|
+
*/
|
|
29
|
+
export declare const RESERVED_CLAIMS: readonly ["sub", "iat", "exp", "nbf", "iss", "aud", "jti", "roles", "typ", "family"];
|
|
30
|
+
export interface TokenPayload {
|
|
31
|
+
sub?: string;
|
|
32
|
+
iat?: number;
|
|
33
|
+
exp?: number;
|
|
34
|
+
nbf?: number;
|
|
35
|
+
iss?: string;
|
|
36
|
+
aud?: string | string[];
|
|
37
|
+
jti?: string;
|
|
38
|
+
roles?: string[];
|
|
39
|
+
typ?: TokenUse;
|
|
40
|
+
family?: string;
|
|
41
|
+
[key: string]: unknown;
|
|
42
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { H3Event } from 'h3';
|
|
2
|
+
export declare function storeContextData<T>(event: H3Event, key: string, value: T): void;
|
|
3
|
+
export declare function getContextData<T>(event: H3Event, key: string): T | undefined;
|
|
4
|
+
export declare function clearContextData(event: H3Event, key: string): void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const CONTEXT_KEY_PREFIX = "authkit_";
|
|
2
|
+
export function storeContextData(event, key, value) {
|
|
3
|
+
event.context[`${CONTEXT_KEY_PREFIX}${key}`] = value;
|
|
4
|
+
}
|
|
5
|
+
export function getContextData(event, key) {
|
|
6
|
+
return event.context[`${CONTEXT_KEY_PREFIX}${key}`];
|
|
7
|
+
}
|
|
8
|
+
export function clearContextData(event, key) {
|
|
9
|
+
delete event.context[`${CONTEXT_KEY_PREFIX}${key}`];
|
|
10
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defu } from "defu";
|
|
2
|
+
import { DEFAULT_RUNTIME_CONFIG as defaultRuntime } from "../types/runtime-config.js";
|
|
3
|
+
export function mergeRuntimeConfig(moduleOptions) {
|
|
4
|
+
const moduleOptionsToRuntimeConfig = {
|
|
5
|
+
nuxtAuthkit: {
|
|
6
|
+
strategy: moduleOptions.strategy,
|
|
7
|
+
strategies: moduleOptions.strategies,
|
|
8
|
+
// Without this the `scrypt` module option never reaches runtimeConfig, and
|
|
9
|
+
// password hashing silently falls back to the driver defaults — an operator
|
|
10
|
+
// hardening the cost parameters would see their config quietly ignored.
|
|
11
|
+
scrypt: moduleOptions.scrypt
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
return defu(
|
|
15
|
+
moduleOptionsToRuntimeConfig,
|
|
16
|
+
defaultRuntime
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hash a password using scrypt
|
|
3
|
+
* @param password - The plain text password to hash
|
|
4
|
+
* @returns The hashed password
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* const hashedPassword = await hashPassword('user_password')
|
|
8
|
+
* ```
|
|
9
|
+
* @more you can configure the scrypt options in `auth.hash.scrypt`
|
|
10
|
+
*/
|
|
11
|
+
export declare function hashPassword(password: string): Promise<string>;
|
|
12
|
+
/**
|
|
13
|
+
* Verify a password against a hashed password
|
|
14
|
+
* @param hashedPassword - The hashed password to verify against
|
|
15
|
+
* @param plainPassword - The plain text password to verify
|
|
16
|
+
* @returns `true` if the password is valid, `false` otherwise
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* const isValid = await verifyPassword(hashedPassword, 'user_password')
|
|
20
|
+
* ```
|
|
21
|
+
* @more you can configure the scrypt options in `auth.hash.scrypt`
|
|
22
|
+
*/
|
|
23
|
+
export declare function verifyPassword(hashedPassword: string, plainPassword: string): Promise<boolean>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Hash } from "@adonisjs/hash";
|
|
2
|
+
import { Scrypt } from "@adonisjs/hash/drivers/scrypt";
|
|
3
|
+
import { useRuntimeConfig } from "#imports";
|
|
4
|
+
let _hash;
|
|
5
|
+
function getHash() {
|
|
6
|
+
if (!_hash) {
|
|
7
|
+
const options = useRuntimeConfig().nuxtAuthkit?.scrypt;
|
|
8
|
+
const scrypt = new Scrypt(options);
|
|
9
|
+
_hash = new Hash(scrypt);
|
|
10
|
+
}
|
|
11
|
+
return _hash;
|
|
12
|
+
}
|
|
13
|
+
export async function hashPassword(password) {
|
|
14
|
+
return await getHash().make(password);
|
|
15
|
+
}
|
|
16
|
+
export async function verifyPassword(hashedPassword, plainPassword) {
|
|
17
|
+
return await getHash().verify(hashedPassword, plainPassword);
|
|
18
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* uuidv7: A JavaScript implementation of UUID version 7
|
|
3
|
+
*
|
|
4
|
+
* Copyright 2021-2024 LiosK
|
|
5
|
+
*
|
|
6
|
+
* @license Apache-2.0
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
/** Represents a UUID as a 16-byte byte array. */
|
|
10
|
+
export declare class UUID {
|
|
11
|
+
readonly bytes: Readonly<Uint8Array>;
|
|
12
|
+
/** @param bytes - The 16-byte byte array representation. */
|
|
13
|
+
private constructor();
|
|
14
|
+
/**
|
|
15
|
+
* Creates an object from the internal representation, a 16-byte byte array
|
|
16
|
+
* containing the binary UUID representation in the big-endian byte order.
|
|
17
|
+
*
|
|
18
|
+
* This method does NOT shallow-copy the argument, and thus the created object
|
|
19
|
+
* holds the reference to the underlying buffer.
|
|
20
|
+
*
|
|
21
|
+
* @throws TypeError if the length of the argument is not 16.
|
|
22
|
+
*/
|
|
23
|
+
static ofInner(bytes: Readonly<Uint8Array>): UUID;
|
|
24
|
+
/**
|
|
25
|
+
* Builds a byte array from UUIDv7 field values.
|
|
26
|
+
*
|
|
27
|
+
* @param unixTsMs - A 48-bit `unix_ts_ms` field value.
|
|
28
|
+
* @param randA - A 12-bit `rand_a` field value.
|
|
29
|
+
* @param randBHi - The higher 30 bits of 62-bit `rand_b` field value.
|
|
30
|
+
* @param randBLo - The lower 32 bits of 62-bit `rand_b` field value.
|
|
31
|
+
* @throws RangeError if any field value is out of the specified range.
|
|
32
|
+
*/
|
|
33
|
+
static fromFieldsV7(unixTsMs: number, randA: number, randBHi: number, randBLo: number): UUID;
|
|
34
|
+
/**
|
|
35
|
+
* Builds a byte array from a string representation.
|
|
36
|
+
*
|
|
37
|
+
* This method accepts the following formats:
|
|
38
|
+
*
|
|
39
|
+
* - 32-digit hexadecimal format without hyphens: `0189dcd553117d408db09496a2eef37b`
|
|
40
|
+
* - 8-4-4-4-12 hyphenated format: `0189dcd5-5311-7d40-8db0-9496a2eef37b`
|
|
41
|
+
* - Hyphenated format with surrounding braces: `{0189dcd5-5311-7d40-8db0-9496a2eef37b}`
|
|
42
|
+
* - RFC 9562 URN format: `urn:uuid:0189dcd5-5311-7d40-8db0-9496a2eef37b`
|
|
43
|
+
*
|
|
44
|
+
* Leading and trailing whitespaces represents an error.
|
|
45
|
+
*
|
|
46
|
+
* @throws SyntaxError if the argument could not parse as a valid UUID string.
|
|
47
|
+
*/
|
|
48
|
+
static parse(uuid: string): UUID;
|
|
49
|
+
/**
|
|
50
|
+
* @returns The 8-4-4-4-12 canonical hexadecimal string representation
|
|
51
|
+
* (`0189dcd5-5311-7d40-8db0-9496a2eef37b`).
|
|
52
|
+
*/
|
|
53
|
+
toString(): string;
|
|
54
|
+
/**
|
|
55
|
+
* @returns The 32-digit hexadecimal representation without hyphens
|
|
56
|
+
* (`0189dcd553117d408db09496a2eef37b`).
|
|
57
|
+
*/
|
|
58
|
+
toHex(): string;
|
|
59
|
+
/** @returns The 8-4-4-4-12 canonical hexadecimal string representation. */
|
|
60
|
+
toJSON(): string;
|
|
61
|
+
/**
|
|
62
|
+
* Reports the variant field value of the UUID or, if appropriate, "NIL" or
|
|
63
|
+
* "MAX".
|
|
64
|
+
*
|
|
65
|
+
* For convenience, this method reports "NIL" or "MAX" if `this` represents
|
|
66
|
+
* the Nil or Max UUID, although the Nil and Max UUIDs are technically
|
|
67
|
+
* subsumed under the variants `0b0` and `0b111`, respectively.
|
|
68
|
+
*/
|
|
69
|
+
getVariant(): "VAR_0" | "VAR_10" | "VAR_110" | "VAR_RESERVED" | "NIL" | "MAX";
|
|
70
|
+
/**
|
|
71
|
+
* Returns the version field value of the UUID or `undefined` if the UUID does
|
|
72
|
+
* not have the variant field value of `0b10`.
|
|
73
|
+
*/
|
|
74
|
+
getVersion(): number | undefined;
|
|
75
|
+
/** Creates an object from `this`. */
|
|
76
|
+
clone(): UUID;
|
|
77
|
+
/** Returns true if `this` is equivalent to `other`. */
|
|
78
|
+
equals(other: UUID): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Returns a negative integer, zero, or positive integer if `this` is less
|
|
81
|
+
* than, equal to, or greater than `other`, respectively.
|
|
82
|
+
*/
|
|
83
|
+
compareTo(other: UUID): number;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Encapsulates the monotonic counter state.
|
|
87
|
+
*
|
|
88
|
+
* This class provides APIs to utilize a separate counter state from that of the
|
|
89
|
+
* global generator used by {@link uuidv7} and {@link uuidv7obj}. In addition to
|
|
90
|
+
* the default {@link generate} method, this class has {@link generateOrAbort}
|
|
91
|
+
* that is useful to absolutely guarantee the monotonically increasing order of
|
|
92
|
+
* generated UUIDs. See their respective documentation for details.
|
|
93
|
+
*/
|
|
94
|
+
export declare class V7Generator {
|
|
95
|
+
private timestamp;
|
|
96
|
+
private counter;
|
|
97
|
+
/** The random number generator used by the generator. */
|
|
98
|
+
private readonly random;
|
|
99
|
+
/**
|
|
100
|
+
* Creates a generator object with the default random number generator, or
|
|
101
|
+
* with the specified one if passed as an argument. The specified random
|
|
102
|
+
* number generator should be cryptographically strong and securely seeded.
|
|
103
|
+
*/
|
|
104
|
+
constructor(randomNumberGenerator?: {
|
|
105
|
+
/** Returns a 32-bit random unsigned integer. */
|
|
106
|
+
nextUint32(): number;
|
|
107
|
+
});
|
|
108
|
+
/**
|
|
109
|
+
* Generates a new UUIDv7 object from the current timestamp, or resets the
|
|
110
|
+
* generator upon significant timestamp rollback.
|
|
111
|
+
*
|
|
112
|
+
* This method returns a monotonically increasing UUID by reusing the previous
|
|
113
|
+
* timestamp even if the up-to-date timestamp is smaller than the immediately
|
|
114
|
+
* preceding UUID's. However, when such a clock rollback is considered
|
|
115
|
+
* significant (i.e., by more than ten seconds), this method resets the
|
|
116
|
+
* generator and returns a new UUID based on the given timestamp, breaking the
|
|
117
|
+
* increasing order of UUIDs.
|
|
118
|
+
*
|
|
119
|
+
* See {@link generateOrAbort} for the other mode of generation and
|
|
120
|
+
* {@link generateOrResetCore} for the low-level primitive.
|
|
121
|
+
*/
|
|
122
|
+
generate(): UUID;
|
|
123
|
+
/**
|
|
124
|
+
* Generates a new UUIDv7 object from the current timestamp, or returns
|
|
125
|
+
* `undefined` upon significant timestamp rollback.
|
|
126
|
+
*
|
|
127
|
+
* This method returns a monotonically increasing UUID by reusing the previous
|
|
128
|
+
* timestamp even if the up-to-date timestamp is smaller than the immediately
|
|
129
|
+
* preceding UUID's. However, when such a clock rollback is considered
|
|
130
|
+
* significant (i.e., by more than ten seconds), this method aborts and
|
|
131
|
+
* returns `undefined` immediately.
|
|
132
|
+
*
|
|
133
|
+
* See {@link generate} for the other mode of generation and
|
|
134
|
+
* {@link generateOrAbortCore} for the low-level primitive.
|
|
135
|
+
*/
|
|
136
|
+
generateOrAbort(): UUID | undefined;
|
|
137
|
+
/**
|
|
138
|
+
* Generates a new UUIDv7 object from the `unixTsMs` passed, or resets the
|
|
139
|
+
* generator upon significant timestamp rollback.
|
|
140
|
+
*
|
|
141
|
+
* This method is equivalent to {@link generate} except that it takes a custom
|
|
142
|
+
* timestamp and clock rollback allowance.
|
|
143
|
+
*
|
|
144
|
+
* @param rollbackAllowance - The amount of `unixTsMs` rollback that is
|
|
145
|
+
* considered significant. A suggested value is `10_000` (milliseconds).
|
|
146
|
+
* @throws RangeError if `unixTsMs` is not a 48-bit positive integer.
|
|
147
|
+
*/
|
|
148
|
+
generateOrResetCore(unixTsMs: number, rollbackAllowance: number): UUID;
|
|
149
|
+
/**
|
|
150
|
+
* Generates a new UUIDv7 object from the `unixTsMs` passed, or returns
|
|
151
|
+
* `undefined` upon significant timestamp rollback.
|
|
152
|
+
*
|
|
153
|
+
* This method is equivalent to {@link generateOrAbort} except that it takes a
|
|
154
|
+
* custom timestamp and clock rollback allowance.
|
|
155
|
+
*
|
|
156
|
+
* @param rollbackAllowance - The amount of `unixTsMs` rollback that is
|
|
157
|
+
* considered significant. A suggested value is `10_000` (milliseconds).
|
|
158
|
+
* @throws RangeError if `unixTsMs` is not a 48-bit positive integer.
|
|
159
|
+
*/
|
|
160
|
+
generateOrAbortCore(unixTsMs: number, rollbackAllowance: number): UUID | undefined;
|
|
161
|
+
/** Initializes the counter at a 42-bit random integer. */
|
|
162
|
+
private resetCounter;
|
|
163
|
+
/**
|
|
164
|
+
* Generates a new UUIDv4 object utilizing the random number generator inside.
|
|
165
|
+
*
|
|
166
|
+
* @internal
|
|
167
|
+
*/
|
|
168
|
+
generateV4(): UUID;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Generates a UUIDv7 string.
|
|
172
|
+
*
|
|
173
|
+
* @returns The 8-4-4-4-12 canonical hexadecimal string representation
|
|
174
|
+
* ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx").
|
|
175
|
+
*/
|
|
176
|
+
export declare const uuidv7: () => string;
|
|
177
|
+
/** Generates a UUIDv7 object. */
|
|
178
|
+
export declare const uuidv7obj: () => UUID;
|
|
179
|
+
/**
|
|
180
|
+
* Generates a UUIDv4 string.
|
|
181
|
+
*
|
|
182
|
+
* @returns The 8-4-4-4-12 canonical hexadecimal string representation
|
|
183
|
+
* ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx").
|
|
184
|
+
*/
|
|
185
|
+
export declare const uuidv4: () => string;
|
|
186
|
+
/** Generates a UUIDv4 object. */
|
|
187
|
+
export declare const uuidv4obj: () => UUID;
|