@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,122 @@
1
+ import type { TokenPayload } from '../../types/token.js';
2
+ export interface JWTCryptoConfig {
3
+ /**
4
+ * RSA private key in PEM format for signing tokens
5
+ */
6
+ privateKey?: string;
7
+ /**
8
+ * RSA public key in PEM format for verifying tokens
9
+ */
10
+ publicKey?: string;
11
+ /**
12
+ * Algorithm to use for signing (default: RS256)
13
+ */
14
+ algorithm?: 'RS256' | 'RS384' | 'RS512';
15
+ /**
16
+ * Reject tokens longer than this before doing any parsing or signature work.
17
+ * @default 16384
18
+ */
19
+ maxTokenLength?: number;
20
+ }
21
+ export interface JWTHeader {
22
+ alg: string;
23
+ typ: string;
24
+ }
25
+ /**
26
+ * Why a token was rejected. Callers map these to a stable, non-leaking error
27
+ * taxonomy — a malformed or badly-signed token is a hard failure, never a
28
+ * "recoverable" one that a client should retry.
29
+ */
30
+ export type JWTCryptoErrorCode = 'TOKEN_MALFORMED' | 'TOKEN_SIGNATURE_INVALID' | 'TOKEN_ALGORITHM_MISMATCH' | 'TOKEN_TOO_LARGE' | 'KEY_UNAVAILABLE';
31
+ /**
32
+ * A token-level failure carrying a machine-readable code.
33
+ *
34
+ * The `message` is for server logs only — it distinguishes malformed-from-
35
+ * bad-signature and must never be relayed to a client, or it becomes an oracle.
36
+ */
37
+ export declare class JWTCryptoError extends Error {
38
+ readonly code: JWTCryptoErrorCode;
39
+ constructor(code: JWTCryptoErrorCode, message: string);
40
+ }
41
+ /**
42
+ * Secure JWT token handler using RSA cryptography
43
+ * Supports RS256, RS384, and RS512 algorithms
44
+ */
45
+ export declare class JWTCrypto {
46
+ private privateKey?;
47
+ private publicKey?;
48
+ private algorithm;
49
+ private maxTokenLength;
50
+ constructor(config: JWTCryptoConfig);
51
+ /**
52
+ * Sign and encode a JWT token
53
+ * @throws Error if private key is not configured
54
+ */
55
+ sign(payload: TokenPayload): string;
56
+ /**
57
+ * Verify and decode a JWT token
58
+ * @throws Error if token is invalid or public key is not configured
59
+ */
60
+ verify(token: string): TokenPayload;
61
+ /**
62
+ * Decode a token WITHOUT verifying its signature.
63
+ *
64
+ * The returned claims are attacker-controlled and must never be used for an
65
+ * authentication or authorization decision. Use {@link verify} for anything
66
+ * that matters. Kept only for diagnostics.
67
+ *
68
+ * @internal
69
+ * @deprecated Use {@link verify}. This performs no signature check.
70
+ */
71
+ unsafeDecodeNoVerify(token: string): TokenPayload | null;
72
+ /**
73
+ * Decode token without verification (use with caution!)
74
+ * Useful for extracting claims before verification or when signature verification is not required
75
+ *
76
+ * @internal
77
+ * @deprecated Use {@link verify}. This performs no signature check, so its
78
+ * output is attacker-controlled.
79
+ */
80
+ decode(token: string): TokenPayload | null;
81
+ private createSignature;
82
+ private verifySignature;
83
+ private getHashAlgorithm;
84
+ private parsePrivateKey;
85
+ private parsePublicKey;
86
+ /**
87
+ * The configured algorithm (RS*) names RSA. An EC or Ed25519 PEM would
88
+ * otherwise be accepted here and used under an "RS256" label.
89
+ */
90
+ private assertRsaKey;
91
+ /**
92
+ * Encode string to base64url
93
+ */
94
+ private base64UrlEncode;
95
+ /**
96
+ * Decode base64url string to UTF-8 string
97
+ */
98
+ private base64UrlDecode;
99
+ /**
100
+ * Convert binary buffer to base64url (for signatures)
101
+ */
102
+ private bufferToBase64Url;
103
+ /**
104
+ * Convert base64url to binary buffer (for signatures)
105
+ */
106
+ private base64UrlToBuffer;
107
+ /**
108
+ * Generate a new RSA key pair for development/testing
109
+ * In production, use properly generated and stored keys
110
+ *
111
+ * Defaults to 3072 bits: NIST SP 800-57 rates 2048-bit RSA as adequate only
112
+ * through ~2030, which is inside the lifetime of a key minted today.
113
+ */
114
+ static generateKeyPair(modulusLength?: 2048 | 3072 | 4096): {
115
+ privateKey: string;
116
+ publicKey: string;
117
+ };
118
+ /**
119
+ * Validate that a key pair matches (public key can verify tokens signed by private key)
120
+ */
121
+ static validateKeyPair(privateKey: string, publicKey: string): boolean;
122
+ }
@@ -0,0 +1,298 @@
1
+ import { createSign, createVerify, generateKeyPairSync, createPrivateKey, createPublicKey } from "node:crypto";
2
+ export class JWTCryptoError extends Error {
3
+ code;
4
+ constructor(code, message) {
5
+ super(message);
6
+ this.name = "JWTCryptoError";
7
+ this.code = code;
8
+ }
9
+ }
10
+ const SUPPORTED_ALGORITHMS = ["RS256", "RS384", "RS512"];
11
+ const DEFAULT_MAX_TOKEN_LENGTH = 16384;
12
+ export class JWTCrypto {
13
+ privateKey;
14
+ publicKey;
15
+ algorithm;
16
+ maxTokenLength;
17
+ constructor(config) {
18
+ this.algorithm = config.algorithm || "RS256";
19
+ this.maxTokenLength = config.maxTokenLength ?? DEFAULT_MAX_TOKEN_LENGTH;
20
+ if (!SUPPORTED_ALGORITHMS.includes(this.algorithm)) {
21
+ throw new Error(
22
+ `Unsupported JWT algorithm "${this.algorithm}". Supported: ${SUPPORTED_ALGORITHMS.join(", ")}`
23
+ );
24
+ }
25
+ if (config.privateKey) {
26
+ try {
27
+ this.privateKey = this.parsePrivateKey(config.privateKey);
28
+ } catch (error) {
29
+ throw new Error(`Failed to parse private key: ${error instanceof Error ? error.message : "Unknown error"}`);
30
+ }
31
+ }
32
+ if (config.publicKey) {
33
+ try {
34
+ this.publicKey = this.parsePublicKey(config.publicKey);
35
+ } catch (error) {
36
+ throw new Error(`Failed to parse public key: ${error instanceof Error ? error.message : "Unknown error"}`);
37
+ }
38
+ }
39
+ if (!this.privateKey && !this.publicKey) {
40
+ throw new Error("At least one of privateKey or publicKey must be provided");
41
+ }
42
+ }
43
+ /**
44
+ * Sign and encode a JWT token
45
+ * @throws Error if private key is not configured
46
+ */
47
+ sign(payload) {
48
+ if (!this.privateKey) {
49
+ throw new Error("Private key is required for signing tokens");
50
+ }
51
+ const header = {
52
+ alg: this.algorithm,
53
+ typ: "JWT"
54
+ };
55
+ const encodedHeader = this.base64UrlEncode(JSON.stringify(header));
56
+ const encodedPayload = this.base64UrlEncode(JSON.stringify(payload));
57
+ const signatureInput = `${encodedHeader}.${encodedPayload}`;
58
+ const signature = this.createSignature(signatureInput);
59
+ return `${signatureInput}.${signature}`;
60
+ }
61
+ /**
62
+ * Verify and decode a JWT token
63
+ * @throws Error if token is invalid or public key is not configured
64
+ */
65
+ verify(token) {
66
+ if (!this.publicKey) {
67
+ throw new JWTCryptoError("KEY_UNAVAILABLE", "Public key is required for verifying tokens");
68
+ }
69
+ if (typeof token !== "string" || token.length === 0) {
70
+ throw new JWTCryptoError("TOKEN_MALFORMED", "Invalid token format: not a string");
71
+ }
72
+ if (token.length > this.maxTokenLength) {
73
+ throw new JWTCryptoError(
74
+ "TOKEN_TOO_LARGE",
75
+ `Token exceeds maximum length of ${this.maxTokenLength} characters`
76
+ );
77
+ }
78
+ const parts = token.split(".");
79
+ if (parts.length !== 3) {
80
+ throw new JWTCryptoError("TOKEN_MALFORMED", "Invalid token format: expected 3 parts");
81
+ }
82
+ const [encodedHeader, encodedPayload, signature] = parts;
83
+ if (!encodedHeader || !encodedPayload || !signature) {
84
+ throw new JWTCryptoError("TOKEN_MALFORMED", "Invalid token format: missing parts");
85
+ }
86
+ const signatureInput = `${encodedHeader}.${encodedPayload}`;
87
+ const isValid = this.verifySignature(signatureInput, signature);
88
+ if (!isValid) {
89
+ throw new JWTCryptoError("TOKEN_SIGNATURE_INVALID", "Invalid token signature");
90
+ }
91
+ let header;
92
+ try {
93
+ header = JSON.parse(this.base64UrlDecode(encodedHeader));
94
+ } catch {
95
+ throw new JWTCryptoError("TOKEN_MALFORMED", "Invalid token header");
96
+ }
97
+ if (header.alg !== this.algorithm) {
98
+ throw new JWTCryptoError(
99
+ "TOKEN_ALGORITHM_MISMATCH",
100
+ `Algorithm mismatch: expected ${this.algorithm}, got ${header.alg}`
101
+ );
102
+ }
103
+ if (header.typ !== "JWT") {
104
+ throw new JWTCryptoError(
105
+ "TOKEN_MALFORMED",
106
+ `Invalid JOSE header typ: expected "JWT", got ${JSON.stringify(header.typ)}`
107
+ );
108
+ }
109
+ let payload;
110
+ try {
111
+ payload = JSON.parse(this.base64UrlDecode(encodedPayload));
112
+ } catch {
113
+ throw new JWTCryptoError("TOKEN_MALFORMED", "Invalid token payload");
114
+ }
115
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
116
+ throw new JWTCryptoError("TOKEN_MALFORMED", "Invalid token payload: not an object");
117
+ }
118
+ return payload;
119
+ }
120
+ /**
121
+ * Decode a token WITHOUT verifying its signature.
122
+ *
123
+ * The returned claims are attacker-controlled and must never be used for an
124
+ * authentication or authorization decision. Use {@link verify} for anything
125
+ * that matters. Kept only for diagnostics.
126
+ *
127
+ * @internal
128
+ * @deprecated Use {@link verify}. This performs no signature check.
129
+ */
130
+ unsafeDecodeNoVerify(token) {
131
+ return this.decode(token);
132
+ }
133
+ /**
134
+ * Decode token without verification (use with caution!)
135
+ * Useful for extracting claims before verification or when signature verification is not required
136
+ *
137
+ * @internal
138
+ * @deprecated Use {@link verify}. This performs no signature check, so its
139
+ * output is attacker-controlled.
140
+ */
141
+ decode(token) {
142
+ try {
143
+ const parts = token.split(".");
144
+ if (parts.length !== 3) {
145
+ return null;
146
+ }
147
+ if (!parts[0] || !parts[1]) {
148
+ return null;
149
+ }
150
+ const payload = this.base64UrlDecode(parts[1]);
151
+ return JSON.parse(payload);
152
+ } catch {
153
+ return null;
154
+ }
155
+ }
156
+ createSignature(data) {
157
+ if (!this.privateKey) {
158
+ throw new Error("Private key is required for signing");
159
+ }
160
+ const hashAlgorithm = this.getHashAlgorithm();
161
+ const sign = createSign(hashAlgorithm);
162
+ sign.update(data);
163
+ sign.end();
164
+ const signature = sign.sign(this.privateKey);
165
+ return this.bufferToBase64Url(signature);
166
+ }
167
+ verifySignature(data, signature) {
168
+ if (!this.publicKey) {
169
+ throw new Error("Public key is required for verification");
170
+ }
171
+ try {
172
+ const hashAlgorithm = this.getHashAlgorithm();
173
+ const verify = createVerify(hashAlgorithm);
174
+ verify.update(data);
175
+ verify.end();
176
+ const signatureBuffer = this.base64UrlToBuffer(signature);
177
+ return verify.verify(this.publicKey, signatureBuffer);
178
+ } catch {
179
+ return false;
180
+ }
181
+ }
182
+ getHashAlgorithm() {
183
+ switch (this.algorithm) {
184
+ case "RS256":
185
+ return "RSA-SHA256";
186
+ case "RS384":
187
+ return "RSA-SHA384";
188
+ case "RS512":
189
+ return "RSA-SHA512";
190
+ default:
191
+ throw new Error(`Unsupported algorithm: ${this.algorithm}`);
192
+ }
193
+ }
194
+ parsePrivateKey(keyData) {
195
+ const key = createPrivateKey({
196
+ key: keyData,
197
+ format: "pem"
198
+ });
199
+ this.assertRsaKey(key, "private");
200
+ return key;
201
+ }
202
+ parsePublicKey(keyData) {
203
+ const key = createPublicKey({
204
+ key: keyData,
205
+ format: "pem"
206
+ });
207
+ this.assertRsaKey(key, "public");
208
+ return key;
209
+ }
210
+ /**
211
+ * The configured algorithm (RS*) names RSA. An EC or Ed25519 PEM would
212
+ * otherwise be accepted here and used under an "RS256" label.
213
+ */
214
+ assertRsaKey(key, kind) {
215
+ if (key.asymmetricKeyType !== "rsa" && key.asymmetricKeyType !== "rsa-pss") {
216
+ throw new Error(
217
+ `Expected an RSA ${kind} key for ${this.algorithm}, got "${key.asymmetricKeyType}"`
218
+ );
219
+ }
220
+ }
221
+ /**
222
+ * Encode string to base64url
223
+ */
224
+ base64UrlEncode(str) {
225
+ const base64 = Buffer.from(str, "utf-8").toString("base64");
226
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
227
+ }
228
+ /**
229
+ * Decode base64url string to UTF-8 string
230
+ */
231
+ base64UrlDecode(str) {
232
+ let base64 = str.replace(/-/g, "+").replace(/_/g, "/");
233
+ const pad = base64.length % 4;
234
+ if (pad) {
235
+ base64 += "=".repeat(4 - pad);
236
+ }
237
+ return Buffer.from(base64, "base64").toString("utf-8");
238
+ }
239
+ /**
240
+ * Convert binary buffer to base64url (for signatures)
241
+ */
242
+ bufferToBase64Url(buffer) {
243
+ return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
244
+ }
245
+ /**
246
+ * Convert base64url to binary buffer (for signatures)
247
+ */
248
+ base64UrlToBuffer(str) {
249
+ let base64 = str.replace(/-/g, "+").replace(/_/g, "/");
250
+ const pad = base64.length % 4;
251
+ if (pad) {
252
+ base64 += "=".repeat(4 - pad);
253
+ }
254
+ return Buffer.from(base64, "base64");
255
+ }
256
+ /**
257
+ * Generate a new RSA key pair for development/testing
258
+ * In production, use properly generated and stored keys
259
+ *
260
+ * Defaults to 3072 bits: NIST SP 800-57 rates 2048-bit RSA as adequate only
261
+ * through ~2030, which is inside the lifetime of a key minted today.
262
+ */
263
+ static generateKeyPair(modulusLength = 3072) {
264
+ const { publicKey, privateKey } = generateKeyPairSync("rsa", {
265
+ modulusLength,
266
+ publicKeyEncoding: {
267
+ type: "spki",
268
+ format: "pem"
269
+ },
270
+ privateKeyEncoding: {
271
+ type: "pkcs8",
272
+ format: "pem"
273
+ }
274
+ });
275
+ return {
276
+ privateKey,
277
+ publicKey
278
+ };
279
+ }
280
+ /**
281
+ * Validate that a key pair matches (public key can verify tokens signed by private key)
282
+ */
283
+ static validateKeyPair(privateKey, publicKey) {
284
+ try {
285
+ const crypto = new JWTCrypto({ privateKey, publicKey });
286
+ const testPayload = {
287
+ sub: "test",
288
+ iat: Math.floor(Date.now() / 1e3),
289
+ exp: Math.floor(Date.now() / 1e3) + 60
290
+ };
291
+ const token = crypto.sign(testPayload);
292
+ const verified = crypto.verify(token);
293
+ return verified.sub === testPayload.sub;
294
+ } catch {
295
+ return false;
296
+ }
297
+ }
298
+ }
@@ -0,0 +1,68 @@
1
+ import type { NuxtAuthkitCookieOptions } from '../../types/cookie.js';
2
+ /**
3
+ * JWT Strategy Configuration
4
+ */
5
+ export interface JwtStrategyConfig {
6
+ name: string;
7
+ tokens: {
8
+ access: {
9
+ expiresIn: number;
10
+ };
11
+ refresh?: {
12
+ expiresIn: number;
13
+ storageKey?: string;
14
+ cookie?: NuxtAuthkitCookieOptions;
15
+ /**
16
+ * Rotate the refresh token on every successful refresh: a new
17
+ * refresh token is issued, stored via `onStoreRefreshToken`, and
18
+ * the presented one is invalidated via `onRemoveRefreshToken`.
19
+ *
20
+ * Disabling this means a leaked refresh token stays valid for its
21
+ * full lifetime and cannot be contained server-side.
22
+ *
23
+ * @default true
24
+ */
25
+ rotate?: boolean;
26
+ };
27
+ };
28
+ autoRefresh?: {
29
+ enabled: boolean;
30
+ beforeExpiry: number;
31
+ };
32
+ jwt?: {
33
+ issuer?: string;
34
+ audience?: string | string[];
35
+ /**
36
+ * Static claims added to every access token.
37
+ *
38
+ * Reserved claims (`sub`, `exp`, `iat`, `nbf`, `iss`, `aud`, `jti`,
39
+ * `roles`, `typ`, `family`) are rejected at strategy construction —
40
+ * they are computed per request and must not be overridden.
41
+ */
42
+ claims?: Record<string, unknown>;
43
+ algorithm?: 'RS256' | 'RS384' | 'RS512';
44
+ privateKey: string;
45
+ publicKey: string;
46
+ };
47
+ }
48
+ export interface JWTServerRevokeOptions {
49
+ userId?: string;
50
+ exceptCredentialId?: string;
51
+ expiredOnly?: boolean;
52
+ refreshTokenId?: string;
53
+ }
54
+ export interface JWTVerifyOptions {
55
+ accessToken?: string;
56
+ ignoreExpiration?: boolean;
57
+ }
58
+ export interface JWTRefreshOptions {
59
+ /**
60
+ * Override `tokens.refresh.rotate` for this call.
61
+ */
62
+ rotate?: boolean;
63
+ /**
64
+ * @deprecated Use `rotate`. Rotation is now on by default; this flag is
65
+ * honoured only for backwards compatibility with 0.0.x callers.
66
+ */
67
+ refreshToken?: boolean;
68
+ }
File without changes
@@ -0,0 +1,68 @@
1
+ import type { H3Event } from "h3";
2
+ import type { VerificationType } from "../types/2fac.js";
3
+ import type { AuthResult, VerifyAuthResult } from "../types/index.js";
4
+ import type { AuthStorage } from "../storage/types.js";
5
+ import type { AuthkitCredentials } from "../types/authkit-types.js";
6
+ export interface StrategyConfig {
7
+ /** Strategy name */
8
+ name: string;
9
+ /** Enable 2FA support */
10
+ twoFactor?: {
11
+ enabled: boolean;
12
+ methods: VerificationType[];
13
+ /** Grace period before requiring 2FA (in seconds) */
14
+ gracePeriod?: number;
15
+ };
16
+ /** Token configuration (strategy-specific) */
17
+ tokens?: unknown;
18
+ /** Storage configuration */
19
+ storage?: AuthStorage;
20
+ /** Custom options */
21
+ options?: Record<string, unknown>;
22
+ }
23
+ /**
24
+ * Base interface that all authentication strategies must implement
25
+ */
26
+ export interface AuthStrategyGeneral<TCredentials = AuthkitCredentials> {
27
+ /** Strategy name (e.g., 'jwt', 'session', 'oauth') */
28
+ readonly name: string;
29
+ /** Configuration */
30
+ readonly config: StrategyConfig;
31
+ /**
32
+ * Authenticate user with credentials
33
+ * Returns tokens and user data on success
34
+ */
35
+ authenticate(credentials: TCredentials, event?: H3Event, options?: any): Promise<AuthResult>;
36
+ /**
37
+ * Verify a token and return payload
38
+ * Used for protected routes
39
+ */
40
+ verify(event?: H3Event, options?: any): VerifyAuthResult;
41
+ /**
42
+ * Verify a bare token with no request context — WebSocket peers, workers,
43
+ * signed asset URLs. Optional: not every strategy has a context-free token.
44
+ */
45
+ verifyToken?(token: string): VerifyAuthResult;
46
+ /**
47
+ * Mint a session for a subject the app has already identified by other means
48
+ * (OAuth callback, accepted invite, impersonation), bypassing credentials.
49
+ * Optional: strategies without a token pair to hand out need not implement it.
50
+ */
51
+ issueTokens?(userId: string, event?: H3Event, options?: any): Promise<AuthResult>;
52
+ /**
53
+ * Refresh tokens using refresh token
54
+ */
55
+ refresh(event?: H3Event, options?: any): Promise<AuthResult>;
56
+ /**
57
+ * Revoke/invalidate tokens
58
+ * Used during logout
59
+ */
60
+ revoke(event?: H3Event): Promise<void>;
61
+ /**
62
+ * Server-initiated revocation (admin force-logout, scheduled cleanup).
63
+ * Implementations must fail loudly if they cannot actually revoke anything.
64
+ */
65
+ revokeServer?(options?: any, event?: H3Event): Promise<void>;
66
+ }
67
+ export interface IAuthStrategy<TCredentials = AuthkitCredentials> extends AuthStrategyGeneral<TCredentials> {
68
+ }
File without changes
@@ -0,0 +1,32 @@
1
+ export type VerificationType = 'totp' | 'sms' | 'email' | 'backup_code' | 'webauthn' | 'push';
2
+ export interface TwoFactorChallenge {
3
+ /** Unique challenge ID */
4
+ id: string;
5
+ /** Type of 2FA */
6
+ type: VerificationType;
7
+ /** When the challenge expires */
8
+ expiresAt: number;
9
+ /** Additional data needed for the challenge */
10
+ data?: {
11
+ /** For TOTP: QR code data URL (during setup) */
12
+ qrCode?: string;
13
+ /** For TOTP: Secret key (during setup) */
14
+ secret?: string;
15
+ /** For SMS/Email: Masked destination */
16
+ destination?: string;
17
+ /** For WebAuthn: Challenge data */
18
+ challenge?: unknown;
19
+ };
20
+ /** Available methods if multiple 2FA methods enabled */
21
+ availableMethods?: VerificationType[];
22
+ }
23
+ export interface TwoFactorVerification {
24
+ /** The challenge ID */
25
+ challengeId: string;
26
+ /** The verification code/response */
27
+ code: string;
28
+ /** Type of verification being provided */
29
+ type: VerificationType;
30
+ /** Whether to remember this device */
31
+ trustDevice?: boolean;
32
+ }
File without changes
@@ -0,0 +1,6 @@
1
+ export interface AuthkitRole {
2
+ }
3
+ export interface AuthkitUser {
4
+ }
5
+ export interface AuthkitCredentials {
6
+ }
File without changes