@puzzle-ui/auth 0.0.0-stage → 0.5.0
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 +301 -2
- package/dist/LICENSE +21 -0
- package/dist/auth.lifecycle.manager.cjs +835 -0
- package/dist/auth.lifecycle.manager.cjs.map +1 -0
- package/dist/auth.lifecycle.manager.d.cts +115 -0
- package/dist/auth.lifecycle.manager.d.ts +115 -0
- package/dist/auth.lifecycle.manager.js +835 -0
- package/dist/auth.lifecycle.manager.js.map +1 -0
- package/dist/auth.manager.cjs +454 -0
- package/dist/auth.manager.cjs.map +1 -0
- package/dist/auth.manager.d.cts +54 -0
- package/dist/auth.manager.d.ts +54 -0
- package/dist/auth.manager.js +454 -0
- package/dist/auth.manager.js.map +1 -0
- package/dist/auth.mfa.manager.cjs +1488 -0
- package/dist/auth.mfa.manager.cjs.map +1 -0
- package/dist/auth.mfa.manager.d.cts +100 -0
- package/dist/auth.mfa.manager.d.ts +100 -0
- package/dist/auth.mfa.manager.js +1488 -0
- package/dist/auth.mfa.manager.js.map +1 -0
- package/dist/auth.rate-limit.cjs +78 -0
- package/dist/auth.rate-limit.cjs.map +1 -0
- package/dist/auth.rate-limit.d.cts +24 -0
- package/dist/auth.rate-limit.d.ts +24 -0
- package/dist/auth.rate-limit.js +78 -0
- package/dist/auth.rate-limit.js.map +1 -0
- package/dist/auth.step-up.manager.cjs +269 -0
- package/dist/auth.step-up.manager.cjs.map +1 -0
- package/dist/auth.step-up.manager.d.cts +74 -0
- package/dist/auth.step-up.manager.d.ts +74 -0
- package/dist/auth.step-up.manager.js +268 -0
- package/dist/auth.step-up.manager.js.map +1 -0
- package/dist/auth.storage.cjs +164 -0
- package/dist/auth.storage.cjs.map +1 -0
- package/dist/auth.storage.d.cts +29 -0
- package/dist/auth.storage.d.ts +29 -0
- package/dist/auth.storage.js +148 -0
- package/dist/auth.storage.js.map +1 -0
- package/dist/errors/auth.errors.cjs +101 -0
- package/dist/errors/auth.errors.cjs.map +1 -0
- package/dist/errors/auth.errors.d.cts +62 -0
- package/dist/errors/auth.errors.d.ts +62 -0
- package/dist/errors/auth.errors.js +90 -0
- package/dist/errors/auth.errors.js.map +1 -0
- package/dist/index.cjs +54 -0
- package/dist/index.d.cts +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +13 -0
- package/dist/providers/mfa-provider.types.d.cts +66 -0
- package/dist/providers/mfa-provider.types.d.ts +66 -0
- package/dist/providers/provider.types.d.cts +34 -0
- package/dist/providers/provider.types.d.ts +34 -0
- package/dist/providers/simplewebauthn-provider.cjs +185 -0
- package/dist/providers/simplewebauthn-provider.cjs.map +1 -0
- package/dist/providers/simplewebauthn-provider.d.cts +35 -0
- package/dist/providers/simplewebauthn-provider.d.ts +35 -0
- package/dist/providers/simplewebauthn-provider.js +185 -0
- package/dist/providers/simplewebauthn-provider.js.map +1 -0
- package/dist/providers/webcrypto-secret-protector.cjs +118 -0
- package/dist/providers/webcrypto-secret-protector.cjs.map +1 -0
- package/dist/providers/webcrypto-secret-protector.d.cts +14 -0
- package/dist/providers/webcrypto-secret-protector.d.ts +14 -0
- package/dist/providers/webcrypto-secret-protector.js +118 -0
- package/dist/providers/webcrypto-secret-protector.js.map +1 -0
- package/dist/types/auth-lifecycle.types.d.cts +53 -0
- package/dist/types/auth-lifecycle.types.d.ts +53 -0
- package/dist/types/auth-manager.types.d.cts +106 -0
- package/dist/types/auth-manager.types.d.ts +106 -0
- package/dist/types/credential.types.d.cts +9 -0
- package/dist/types/credential.types.d.ts +9 -0
- package/dist/types/mfa.types.d.cts +244 -0
- package/dist/types/mfa.types.d.ts +244 -0
- package/dist/types/state.types.d.cts +33 -0
- package/dist/types/state.types.d.ts +33 -0
- package/dist/types/user.types.d.cts +9 -0
- package/dist/types/user.types.d.ts +9 -0
- package/dist/utils/auth-crypto.utils.cjs +38 -0
- package/dist/utils/auth-crypto.utils.cjs.map +1 -0
- package/dist/utils/auth-crypto.utils.d.cts +4 -0
- package/dist/utils/auth-crypto.utils.d.ts +4 -0
- package/dist/utils/auth-crypto.utils.js +35 -0
- package/dist/utils/auth-crypto.utils.js.map +1 -0
- package/dist/utils/email.utils.cjs +20 -0
- package/dist/utils/email.utils.cjs.map +1 -0
- package/dist/utils/email.utils.d.cts +2 -0
- package/dist/utils/email.utils.d.ts +2 -0
- package/dist/utils/email.utils.js +19 -0
- package/dist/utils/email.utils.js.map +1 -0
- package/dist/utils/totp.utils.cjs +145 -0
- package/dist/utils/totp.utils.cjs.map +1 -0
- package/dist/utils/totp.utils.d.cts +26 -0
- package/dist/utils/totp.utils.d.ts +26 -0
- package/dist/utils/totp.utils.js +140 -0
- package/dist/utils/totp.utils.js.map +1 -0
- package/package.json +45 -4
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export type ProtectedAuthSecret = {
|
|
2
|
+
readonly ciphertext: string;
|
|
3
|
+
readonly iv: string;
|
|
4
|
+
readonly keyId: string;
|
|
5
|
+
};
|
|
6
|
+
export interface AuthSecretProtector {
|
|
7
|
+
encrypt(plaintext: string): Promise<ProtectedAuthSecret>;
|
|
8
|
+
decrypt(secret: ProtectedAuthSecret): Promise<string>;
|
|
9
|
+
}
|
|
10
|
+
export type WebAuthnOptionsJSON = Readonly<Record<string, unknown>>;
|
|
11
|
+
export type WebAuthnRegistrationCredential = {
|
|
12
|
+
readonly credentialId: string;
|
|
13
|
+
readonly publicKey: string;
|
|
14
|
+
readonly counter: number;
|
|
15
|
+
readonly transports?: readonly string[];
|
|
16
|
+
};
|
|
17
|
+
export type WebAuthnRegistrationVerification = {
|
|
18
|
+
readonly verified: boolean;
|
|
19
|
+
readonly userVerified: boolean;
|
|
20
|
+
readonly credential?: WebAuthnRegistrationCredential;
|
|
21
|
+
};
|
|
22
|
+
export type WebAuthnAuthenticationVerification = {
|
|
23
|
+
readonly verified: boolean;
|
|
24
|
+
readonly userVerified: boolean;
|
|
25
|
+
readonly credentialId: string;
|
|
26
|
+
readonly newCounter: number;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Server-side WebAuthn adapter.
|
|
30
|
+
*
|
|
31
|
+
* Implement this with a maintained WebAuthn server implementation.
|
|
32
|
+
* The adapter is responsible for cryptographic verification, including
|
|
33
|
+
* signatures, challenge binding, origin, RP ID and authenticator data.
|
|
34
|
+
*
|
|
35
|
+
* All challenges must be supplied by Puzzle Auth rather than generated
|
|
36
|
+
* independently by the provider.
|
|
37
|
+
*/
|
|
38
|
+
export interface WebAuthnProvider {
|
|
39
|
+
generateRegistrationOptions(input: {
|
|
40
|
+
readonly challenge: string;
|
|
41
|
+
readonly rpId: string;
|
|
42
|
+
readonly rpName: string;
|
|
43
|
+
readonly userId: string;
|
|
44
|
+
readonly userName: string;
|
|
45
|
+
readonly excludeCredentialIds: readonly string[];
|
|
46
|
+
}): Promise<WebAuthnOptionsJSON>;
|
|
47
|
+
verifyRegistrationResponse(input: {
|
|
48
|
+
readonly response: unknown;
|
|
49
|
+
readonly expectedChallenge: string;
|
|
50
|
+
readonly expectedOrigin: string;
|
|
51
|
+
readonly expectedRpId: string;
|
|
52
|
+
}): Promise<WebAuthnRegistrationVerification>;
|
|
53
|
+
generateAuthenticationOptions(input: {
|
|
54
|
+
readonly challenge: string;
|
|
55
|
+
readonly rpId: string;
|
|
56
|
+
readonly allowCredentialIds?: readonly string[];
|
|
57
|
+
readonly userVerification: "required";
|
|
58
|
+
}): Promise<WebAuthnOptionsJSON>;
|
|
59
|
+
verifyAuthenticationResponse(input: {
|
|
60
|
+
readonly response: unknown;
|
|
61
|
+
readonly expectedChallenge: string;
|
|
62
|
+
readonly expectedOrigin: string;
|
|
63
|
+
readonly expectedRpId: string;
|
|
64
|
+
readonly credential: WebAuthnRegistrationCredential;
|
|
65
|
+
}): Promise<WebAuthnAuthenticationVerification>;
|
|
66
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export type ProtectedAuthSecret = {
|
|
2
|
+
readonly ciphertext: string;
|
|
3
|
+
readonly iv: string;
|
|
4
|
+
readonly keyId: string;
|
|
5
|
+
};
|
|
6
|
+
export interface AuthSecretProtector {
|
|
7
|
+
encrypt(plaintext: string): Promise<ProtectedAuthSecret>;
|
|
8
|
+
decrypt(secret: ProtectedAuthSecret): Promise<string>;
|
|
9
|
+
}
|
|
10
|
+
export type WebAuthnOptionsJSON = Readonly<Record<string, unknown>>;
|
|
11
|
+
export type WebAuthnRegistrationCredential = {
|
|
12
|
+
readonly credentialId: string;
|
|
13
|
+
readonly publicKey: string;
|
|
14
|
+
readonly counter: number;
|
|
15
|
+
readonly transports?: readonly string[];
|
|
16
|
+
};
|
|
17
|
+
export type WebAuthnRegistrationVerification = {
|
|
18
|
+
readonly verified: boolean;
|
|
19
|
+
readonly userVerified: boolean;
|
|
20
|
+
readonly credential?: WebAuthnRegistrationCredential;
|
|
21
|
+
};
|
|
22
|
+
export type WebAuthnAuthenticationVerification = {
|
|
23
|
+
readonly verified: boolean;
|
|
24
|
+
readonly userVerified: boolean;
|
|
25
|
+
readonly credentialId: string;
|
|
26
|
+
readonly newCounter: number;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Server-side WebAuthn adapter.
|
|
30
|
+
*
|
|
31
|
+
* Implement this with a maintained WebAuthn server implementation.
|
|
32
|
+
* The adapter is responsible for cryptographic verification, including
|
|
33
|
+
* signatures, challenge binding, origin, RP ID and authenticator data.
|
|
34
|
+
*
|
|
35
|
+
* All challenges must be supplied by Puzzle Auth rather than generated
|
|
36
|
+
* independently by the provider.
|
|
37
|
+
*/
|
|
38
|
+
export interface WebAuthnProvider {
|
|
39
|
+
generateRegistrationOptions(input: {
|
|
40
|
+
readonly challenge: string;
|
|
41
|
+
readonly rpId: string;
|
|
42
|
+
readonly rpName: string;
|
|
43
|
+
readonly userId: string;
|
|
44
|
+
readonly userName: string;
|
|
45
|
+
readonly excludeCredentialIds: readonly string[];
|
|
46
|
+
}): Promise<WebAuthnOptionsJSON>;
|
|
47
|
+
verifyRegistrationResponse(input: {
|
|
48
|
+
readonly response: unknown;
|
|
49
|
+
readonly expectedChallenge: string;
|
|
50
|
+
readonly expectedOrigin: string;
|
|
51
|
+
readonly expectedRpId: string;
|
|
52
|
+
}): Promise<WebAuthnRegistrationVerification>;
|
|
53
|
+
generateAuthenticationOptions(input: {
|
|
54
|
+
readonly challenge: string;
|
|
55
|
+
readonly rpId: string;
|
|
56
|
+
readonly allowCredentialIds?: readonly string[];
|
|
57
|
+
readonly userVerification: "required";
|
|
58
|
+
}): Promise<WebAuthnOptionsJSON>;
|
|
59
|
+
verifyAuthenticationResponse(input: {
|
|
60
|
+
readonly response: unknown;
|
|
61
|
+
readonly expectedChallenge: string;
|
|
62
|
+
readonly expectedOrigin: string;
|
|
63
|
+
readonly expectedRpId: string;
|
|
64
|
+
readonly credential: WebAuthnRegistrationCredential;
|
|
65
|
+
}): Promise<WebAuthnAuthenticationVerification>;
|
|
66
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type PasswordHash = {
|
|
2
|
+
readonly hash: string;
|
|
3
|
+
readonly algorithm: "argon2id";
|
|
4
|
+
readonly parameters: Readonly<Record<string, number | string>>;
|
|
5
|
+
};
|
|
6
|
+
export interface PasswordHasher {
|
|
7
|
+
hash(password: string): Promise<PasswordHash>;
|
|
8
|
+
verify(password: string, stored: PasswordHash): Promise<boolean>;
|
|
9
|
+
}
|
|
10
|
+
export type EmailMessage = {
|
|
11
|
+
readonly to: string;
|
|
12
|
+
readonly subject: string;
|
|
13
|
+
readonly template: string;
|
|
14
|
+
readonly variables: Readonly<Record<string, string>>;
|
|
15
|
+
};
|
|
16
|
+
export interface EmailProvider {
|
|
17
|
+
send(message: EmailMessage): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
export interface RateLimitProvider {
|
|
20
|
+
consume(input: {
|
|
21
|
+
readonly key: string;
|
|
22
|
+
readonly limit: number;
|
|
23
|
+
readonly windowSeconds: number;
|
|
24
|
+
}): Promise<{
|
|
25
|
+
readonly allowed: boolean;
|
|
26
|
+
readonly remaining: number;
|
|
27
|
+
readonly resetAt: Date;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
export interface PasswordHasher {
|
|
31
|
+
hash(password: string): Promise<PasswordHash>;
|
|
32
|
+
verify(password: string, stored: PasswordHash): Promise<boolean>;
|
|
33
|
+
needsRehash?(stored: PasswordHash): boolean | Promise<boolean>;
|
|
34
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type PasswordHash = {
|
|
2
|
+
readonly hash: string;
|
|
3
|
+
readonly algorithm: "argon2id";
|
|
4
|
+
readonly parameters: Readonly<Record<string, number | string>>;
|
|
5
|
+
};
|
|
6
|
+
export interface PasswordHasher {
|
|
7
|
+
hash(password: string): Promise<PasswordHash>;
|
|
8
|
+
verify(password: string, stored: PasswordHash): Promise<boolean>;
|
|
9
|
+
}
|
|
10
|
+
export type EmailMessage = {
|
|
11
|
+
readonly to: string;
|
|
12
|
+
readonly subject: string;
|
|
13
|
+
readonly template: string;
|
|
14
|
+
readonly variables: Readonly<Record<string, string>>;
|
|
15
|
+
};
|
|
16
|
+
export interface EmailProvider {
|
|
17
|
+
send(message: EmailMessage): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
export interface RateLimitProvider {
|
|
20
|
+
consume(input: {
|
|
21
|
+
readonly key: string;
|
|
22
|
+
readonly limit: number;
|
|
23
|
+
readonly windowSeconds: number;
|
|
24
|
+
}): Promise<{
|
|
25
|
+
readonly allowed: boolean;
|
|
26
|
+
readonly remaining: number;
|
|
27
|
+
readonly resetAt: Date;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
export interface PasswordHasher {
|
|
31
|
+
hash(password: string): Promise<PasswordHash>;
|
|
32
|
+
verify(password: string, stored: PasswordHash): Promise<boolean>;
|
|
33
|
+
needsRehash?(stored: PasswordHash): boolean | Promise<boolean>;
|
|
34
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
const require_auth_errors = require("../errors/auth.errors.cjs");
|
|
2
|
+
let _simplewebauthn_server = require("@simplewebauthn/server");
|
|
3
|
+
// src/providers/simplewebauthn-provider.ts
|
|
4
|
+
const BASE64URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
5
|
+
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
6
|
+
const encodeBase64Url = (input) => {
|
|
7
|
+
let output = "";
|
|
8
|
+
let index = 0;
|
|
9
|
+
while (index + 2 < input.length) {
|
|
10
|
+
const first = input[index++];
|
|
11
|
+
const second = input[index++];
|
|
12
|
+
const third = input[index++];
|
|
13
|
+
output += BASE64URL_ALPHABET.charAt(first >> 2);
|
|
14
|
+
output += BASE64URL_ALPHABET.charAt((first & 3) << 4 | second >> 4);
|
|
15
|
+
output += BASE64URL_ALPHABET.charAt((second & 15) << 2 | third >> 6);
|
|
16
|
+
output += BASE64URL_ALPHABET.charAt(third & 63);
|
|
17
|
+
}
|
|
18
|
+
if (index < input.length) {
|
|
19
|
+
const first = input[index++];
|
|
20
|
+
output += BASE64URL_ALPHABET.charAt(first >> 2);
|
|
21
|
+
if (index < input.length) {
|
|
22
|
+
const second = input[index];
|
|
23
|
+
output += BASE64URL_ALPHABET.charAt((first & 3) << 4 | second >> 4);
|
|
24
|
+
output += BASE64URL_ALPHABET.charAt((second & 15) << 2);
|
|
25
|
+
} else output += BASE64URL_ALPHABET.charAt((first & 3) << 4);
|
|
26
|
+
}
|
|
27
|
+
return output;
|
|
28
|
+
};
|
|
29
|
+
const decodeBase64Url = (value, errorMessage = "The stored passkey public key is invalid.") => {
|
|
30
|
+
if (typeof value !== "string" || value.length === 0 || value.length % 4 === 1 || !/^[A-Za-z0-9_-]+$/.test(value)) throw new require_auth_errors.AuthValidationError(errorMessage);
|
|
31
|
+
const output = [];
|
|
32
|
+
let buffer = 0;
|
|
33
|
+
let bits = 0;
|
|
34
|
+
for (const character of value) {
|
|
35
|
+
const decoded = BASE64URL_ALPHABET.indexOf(character);
|
|
36
|
+
if (decoded < 0) throw new require_auth_errors.AuthValidationError(errorMessage);
|
|
37
|
+
buffer = buffer << 6 | decoded;
|
|
38
|
+
bits += 6;
|
|
39
|
+
if (bits >= 8) {
|
|
40
|
+
bits -= 8;
|
|
41
|
+
output.push(buffer >>> bits & 255);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return new Uint8Array(output);
|
|
45
|
+
};
|
|
46
|
+
const toArrayBuffer = (bytes) => {
|
|
47
|
+
const buffer = new ArrayBuffer(bytes.byteLength);
|
|
48
|
+
new Uint8Array(buffer).set(bytes);
|
|
49
|
+
return buffer;
|
|
50
|
+
};
|
|
51
|
+
const toRegistrationResponse = (value) => {
|
|
52
|
+
if (!isRecord(value) || typeof value.id !== "string" || typeof value.rawId !== "string" || value.type !== "public-key" || !isRecord(value.response)) throw new require_auth_errors.AuthValidationError("The passkey registration response is invalid.");
|
|
53
|
+
return value;
|
|
54
|
+
};
|
|
55
|
+
const toAuthenticationResponse = (value) => {
|
|
56
|
+
if (!isRecord(value) || typeof value.id !== "string" || typeof value.rawId !== "string" || value.type !== "public-key" || !isRecord(value.response)) throw new require_auth_errors.AuthValidationError("The passkey authentication response is invalid.");
|
|
57
|
+
return value;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Derives a stable, opaque WebAuthn user handle from the internal Puzzle user ID.
|
|
61
|
+
*
|
|
62
|
+
* WebAuthn user handles are bytes, not application IDs. Hashing also prevents
|
|
63
|
+
* the internal user ID from being directly exposed in authenticator data.
|
|
64
|
+
*/
|
|
65
|
+
const deriveWebAuthnUserId = async (userId) => {
|
|
66
|
+
if (typeof userId !== "string" || userId.trim().length === 0) throw new require_auth_errors.AuthValidationError("A valid WebAuthn user ID is required.");
|
|
67
|
+
const cryptoApi = globalThis.crypto;
|
|
68
|
+
if (!cryptoApi?.subtle) throw new require_auth_errors.AuthConfigurationError("This runtime does not provide the required Web Crypto APIs.");
|
|
69
|
+
const input = new TextEncoder().encode(`puzzle-webauthn-user:v1:${userId}`);
|
|
70
|
+
const digest = await cryptoApi.subtle.digest("SHA-256", toArrayBuffer(input));
|
|
71
|
+
return new Uint8Array(digest);
|
|
72
|
+
};
|
|
73
|
+
const validateChallenge = (challenge) => {
|
|
74
|
+
if (typeof challenge !== "string" || challenge.length < 32 || challenge.length > 256 || !/^[A-Za-z0-9_-]+$/.test(challenge)) throw new require_auth_errors.AuthValidationError("A valid WebAuthn challenge is required.");
|
|
75
|
+
};
|
|
76
|
+
const validateRpId = (rpId) => {
|
|
77
|
+
if (typeof rpId !== "string" || rpId.trim().length === 0 || rpId.length > 253 || rpId.includes("/") || rpId.includes(":")) throw new require_auth_errors.AuthConfigurationError("The WebAuthn RP ID is invalid.");
|
|
78
|
+
};
|
|
79
|
+
var SimpleWebAuthnProvider = class {
|
|
80
|
+
async generateRegistrationOptions(input) {
|
|
81
|
+
validateChallenge(input.challenge);
|
|
82
|
+
validateRpId(input.rpId);
|
|
83
|
+
if (typeof input.rpName !== "string" || input.rpName.trim().length === 0 || typeof input.userName !== "string" || input.userName.trim().length === 0) throw new require_auth_errors.AuthValidationError("A WebAuthn RP name and user name are required.");
|
|
84
|
+
const excludeCredentials = input.excludeCredentialIds.map((id) => {
|
|
85
|
+
if (!id || !/^[A-Za-z0-9_-]+$/.test(id)) throw new require_auth_errors.AuthValidationError("A stored passkey credential ID is invalid.");
|
|
86
|
+
return { id };
|
|
87
|
+
});
|
|
88
|
+
const options = await (0, _simplewebauthn_server.generateRegistrationOptions)({
|
|
89
|
+
rpID: input.rpId,
|
|
90
|
+
rpName: input.rpName.trim(),
|
|
91
|
+
userID: await deriveWebAuthnUserId(input.userId),
|
|
92
|
+
userName: input.userName.trim(),
|
|
93
|
+
userDisplayName: input.userName.trim(),
|
|
94
|
+
challenge: decodeBase64Url(input.challenge, "A valid WebAuthn challenge is required."),
|
|
95
|
+
attestationType: "none",
|
|
96
|
+
authenticatorSelection: {
|
|
97
|
+
residentKey: "required",
|
|
98
|
+
userVerification: "required"
|
|
99
|
+
},
|
|
100
|
+
excludeCredentials
|
|
101
|
+
});
|
|
102
|
+
if (options.challenge !== input.challenge) throw new require_auth_errors.AuthConfigurationError("SimpleWebAuthn returned an unexpected registration challenge.");
|
|
103
|
+
return options;
|
|
104
|
+
}
|
|
105
|
+
async verifyRegistrationResponse(input) {
|
|
106
|
+
validateChallenge(input.expectedChallenge);
|
|
107
|
+
validateRpId(input.expectedRpId);
|
|
108
|
+
if (typeof input.expectedOrigin !== "string" || input.expectedOrigin.length === 0) throw new require_auth_errors.AuthConfigurationError("A WebAuthn verification origin is required.");
|
|
109
|
+
const response = toRegistrationResponse(input.response);
|
|
110
|
+
const verification = await (0, _simplewebauthn_server.verifyRegistrationResponse)({
|
|
111
|
+
response,
|
|
112
|
+
expectedChallenge: input.expectedChallenge,
|
|
113
|
+
expectedOrigin: input.expectedOrigin,
|
|
114
|
+
expectedRPID: input.expectedRpId,
|
|
115
|
+
requireUserVerification: true
|
|
116
|
+
});
|
|
117
|
+
if (!verification.verified) return {
|
|
118
|
+
verified: false,
|
|
119
|
+
userVerified: false
|
|
120
|
+
};
|
|
121
|
+
const registration = verification.registrationInfo;
|
|
122
|
+
const credential = registration.credential;
|
|
123
|
+
return {
|
|
124
|
+
verified: true,
|
|
125
|
+
userVerified: registration.userVerified,
|
|
126
|
+
credential: {
|
|
127
|
+
credentialId: credential.id,
|
|
128
|
+
publicKey: encodeBase64Url(credential.publicKey),
|
|
129
|
+
counter: credential.counter,
|
|
130
|
+
transports: credential.transports ?? []
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
async generateAuthenticationOptions(input) {
|
|
135
|
+
validateChallenge(input.challenge);
|
|
136
|
+
validateRpId(input.rpId);
|
|
137
|
+
const allowCredentials = input.allowCredentialIds?.map((id) => {
|
|
138
|
+
if (!id || !/^[A-Za-z0-9_-]+$/.test(id)) throw new require_auth_errors.AuthValidationError("A stored passkey credential ID is invalid.");
|
|
139
|
+
return { id };
|
|
140
|
+
});
|
|
141
|
+
const options = await (0, _simplewebauthn_server.generateAuthenticationOptions)({
|
|
142
|
+
rpID: input.rpId,
|
|
143
|
+
challenge: decodeBase64Url(input.challenge, "A valid WebAuthn challenge is required."),
|
|
144
|
+
userVerification: "required",
|
|
145
|
+
...allowCredentials ? { allowCredentials } : {}
|
|
146
|
+
});
|
|
147
|
+
if (options.challenge !== input.challenge) throw new require_auth_errors.AuthConfigurationError("SimpleWebAuthn returned an unexpected authentication challenge.");
|
|
148
|
+
return options;
|
|
149
|
+
}
|
|
150
|
+
async verifyAuthenticationResponse(input) {
|
|
151
|
+
validateChallenge(input.expectedChallenge);
|
|
152
|
+
validateRpId(input.expectedRpId);
|
|
153
|
+
if (typeof input.expectedOrigin !== "string" || input.expectedOrigin.length === 0) throw new require_auth_errors.AuthConfigurationError("A WebAuthn verification origin is required.");
|
|
154
|
+
const response = toAuthenticationResponse(input.response);
|
|
155
|
+
if (response.id !== input.credential.credentialId) return {
|
|
156
|
+
verified: false,
|
|
157
|
+
userVerified: false,
|
|
158
|
+
credentialId: response.id,
|
|
159
|
+
newCounter: input.credential.counter
|
|
160
|
+
};
|
|
161
|
+
if (!Number.isSafeInteger(input.credential.counter) || input.credential.counter < 0) throw new require_auth_errors.AuthValidationError("The stored passkey counter is invalid.");
|
|
162
|
+
const credential = {
|
|
163
|
+
id: input.credential.credentialId,
|
|
164
|
+
publicKey: decodeBase64Url(input.credential.publicKey),
|
|
165
|
+
counter: input.credential.counter
|
|
166
|
+
};
|
|
167
|
+
const verification = await (0, _simplewebauthn_server.verifyAuthenticationResponse)({
|
|
168
|
+
response,
|
|
169
|
+
expectedChallenge: input.expectedChallenge,
|
|
170
|
+
expectedOrigin: input.expectedOrigin,
|
|
171
|
+
expectedRPID: input.expectedRpId,
|
|
172
|
+
credential,
|
|
173
|
+
requireUserVerification: true
|
|
174
|
+
});
|
|
175
|
+
return {
|
|
176
|
+
verified: verification.verified,
|
|
177
|
+
userVerified: verification.verified && verification.authenticationInfo.userVerified,
|
|
178
|
+
credentialId: verification.authenticationInfo.credentialID,
|
|
179
|
+
newCounter: verification.authenticationInfo.newCounter
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
exports.SimpleWebAuthnProvider = SimpleWebAuthnProvider;
|
|
184
|
+
|
|
185
|
+
//# sourceMappingURL=simplewebauthn-provider.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simplewebauthn-provider.cjs","names":["AuthValidationError","AuthConfigurationError","generateRegistrationOptions","verifyRegistrationResponse","generateAuthenticationOptions","verifyAuthenticationResponse"],"sources":["../../src/providers/simplewebauthn-provider.ts"],"sourcesContent":["import {\n generateAuthenticationOptions,\n generateRegistrationOptions,\n verifyAuthenticationResponse,\n verifyRegistrationResponse,\n type AuthenticationResponseJSON,\n type RegistrationResponseJSON,\n type WebAuthnCredential,\n} from \"@simplewebauthn/server\";\n\nimport {\n AuthConfigurationError,\n AuthValidationError,\n} from \"../errors/auth.errors\";\n\nimport type {\n WebAuthnAuthenticationVerification,\n WebAuthnOptionsJSON,\n WebAuthnProvider,\n WebAuthnRegistrationVerification,\n} from \"./mfa-provider.types\";\n\nconst BASE64URL_ALPHABET =\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_\";\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null;\n\nconst encodeBase64Url = (input: Uint8Array): string => {\n let output = \"\";\n let index = 0;\n\n while (index + 2 < input.length) {\n const first = input[index++]!;\n const second = input[index++]!;\n const third = input[index++]!;\n\n output += BASE64URL_ALPHABET.charAt(first >> 2);\n output += BASE64URL_ALPHABET.charAt(((first & 3) << 4) | (second >> 4));\n output += BASE64URL_ALPHABET.charAt(((second & 15) << 2) | (third >> 6));\n output += BASE64URL_ALPHABET.charAt(third & 63);\n }\n\n if (index < input.length) {\n const first = input[index++]!;\n\n output += BASE64URL_ALPHABET.charAt(first >> 2);\n\n if (index < input.length) {\n const second = input[index]!;\n\n output += BASE64URL_ALPHABET.charAt(((first & 3) << 4) | (second >> 4));\n output += BASE64URL_ALPHABET.charAt((second & 15) << 2);\n } else {\n output += BASE64URL_ALPHABET.charAt((first & 3) << 4);\n }\n }\n\n return output;\n};\n\nconst decodeBase64Url = (\n value: string,\n errorMessage = \"The stored passkey public key is invalid.\",\n): Uint8Array<ArrayBuffer> => {\n if (\n typeof value !== \"string\" ||\n value.length === 0 ||\n value.length % 4 === 1 ||\n !/^[A-Za-z0-9_-]+$/.test(value)\n ) {\n throw new AuthValidationError(errorMessage);\n }\n\n const output: number[] = [];\n let buffer = 0;\n let bits = 0;\n\n for (const character of value) {\n const decoded = BASE64URL_ALPHABET.indexOf(character);\n\n if (decoded < 0) {\n throw new AuthValidationError(errorMessage);\n }\n\n buffer = (buffer << 6) | decoded;\n bits += 6;\n\n if (bits >= 8) {\n bits -= 8;\n output.push((buffer >>> bits) & 255);\n }\n }\n\n return new Uint8Array(output);\n};\n\nconst toArrayBuffer = (bytes: Uint8Array): ArrayBuffer => {\n const buffer = new ArrayBuffer(bytes.byteLength);\n new Uint8Array(buffer).set(bytes);\n\n return buffer;\n};\n\nconst toRegistrationResponse = (value: unknown): RegistrationResponseJSON => {\n if (\n !isRecord(value) ||\n typeof value.id !== \"string\" ||\n typeof value.rawId !== \"string\" ||\n value.type !== \"public-key\" ||\n !isRecord(value.response)\n ) {\n throw new AuthValidationError(\n \"The passkey registration response is invalid.\",\n );\n }\n\n return value as unknown as RegistrationResponseJSON;\n};\n\nconst toAuthenticationResponse = (\n value: unknown,\n): AuthenticationResponseJSON => {\n if (\n !isRecord(value) ||\n typeof value.id !== \"string\" ||\n typeof value.rawId !== \"string\" ||\n value.type !== \"public-key\" ||\n !isRecord(value.response)\n ) {\n throw new AuthValidationError(\n \"The passkey authentication response is invalid.\",\n );\n }\n\n return value as unknown as AuthenticationResponseJSON;\n};\n\n/**\n * Derives a stable, opaque WebAuthn user handle from the internal Puzzle user ID.\n *\n * WebAuthn user handles are bytes, not application IDs. Hashing also prevents\n * the internal user ID from being directly exposed in authenticator data.\n */\nconst deriveWebAuthnUserId = async (\n userId: string,\n): Promise<Uint8Array<ArrayBuffer>> => {\n if (typeof userId !== \"string\" || userId.trim().length === 0) {\n throw new AuthValidationError(\"A valid WebAuthn user ID is required.\");\n }\n\n const cryptoApi = globalThis.crypto;\n\n if (!cryptoApi?.subtle) {\n throw new AuthConfigurationError(\n \"This runtime does not provide the required Web Crypto APIs.\",\n );\n }\n\n const input = new TextEncoder().encode(`puzzle-webauthn-user:v1:${userId}`);\n\n const digest = await cryptoApi.subtle.digest(\"SHA-256\", toArrayBuffer(input));\n\n return new Uint8Array(digest);\n};\n\nconst validateChallenge = (challenge: string): void => {\n if (\n typeof challenge !== \"string\" ||\n challenge.length < 32 ||\n challenge.length > 256 ||\n !/^[A-Za-z0-9_-]+$/.test(challenge)\n ) {\n throw new AuthValidationError(\"A valid WebAuthn challenge is required.\");\n }\n};\n\nconst validateRpId = (rpId: string): void => {\n if (\n typeof rpId !== \"string\" ||\n rpId.trim().length === 0 ||\n rpId.length > 253 ||\n rpId.includes(\"/\") ||\n rpId.includes(\":\")\n ) {\n throw new AuthConfigurationError(\"The WebAuthn RP ID is invalid.\");\n }\n};\n\nexport class SimpleWebAuthnProvider implements WebAuthnProvider {\n async generateRegistrationOptions(input: {\n readonly challenge: string;\n readonly rpId: string;\n readonly rpName: string;\n readonly userId: string;\n readonly userName: string;\n readonly excludeCredentialIds: readonly string[];\n }): Promise<WebAuthnOptionsJSON> {\n validateChallenge(input.challenge);\n validateRpId(input.rpId);\n\n if (\n typeof input.rpName !== \"string\" ||\n input.rpName.trim().length === 0 ||\n typeof input.userName !== \"string\" ||\n input.userName.trim().length === 0\n ) {\n throw new AuthValidationError(\n \"A WebAuthn RP name and user name are required.\",\n );\n }\n\n const excludeCredentials = input.excludeCredentialIds.map((id) => {\n if (!id || !/^[A-Za-z0-9_-]+$/.test(id)) {\n throw new AuthValidationError(\n \"A stored passkey credential ID is invalid.\",\n );\n }\n\n return { id };\n });\n\n const options = await generateRegistrationOptions({\n rpID: input.rpId,\n rpName: input.rpName.trim(),\n userID: await deriveWebAuthnUserId(input.userId),\n userName: input.userName.trim(),\n userDisplayName: input.userName.trim(),\n challenge: decodeBase64Url(\n input.challenge,\n \"A valid WebAuthn challenge is required.\",\n ),\n attestationType: \"none\",\n authenticatorSelection: {\n residentKey: \"required\",\n userVerification: \"required\",\n },\n excludeCredentials,\n });\n\n if (options.challenge !== input.challenge) {\n throw new AuthConfigurationError(\n \"SimpleWebAuthn returned an unexpected registration challenge.\",\n );\n }\n\n return options as unknown as WebAuthnOptionsJSON;\n }\n\n async verifyRegistrationResponse(input: {\n readonly response: unknown;\n readonly expectedChallenge: string;\n readonly expectedOrigin: string;\n readonly expectedRpId: string;\n }): Promise<WebAuthnRegistrationVerification> {\n validateChallenge(input.expectedChallenge);\n validateRpId(input.expectedRpId);\n\n if (\n typeof input.expectedOrigin !== \"string\" ||\n input.expectedOrigin.length === 0\n ) {\n throw new AuthConfigurationError(\n \"A WebAuthn verification origin is required.\",\n );\n }\n\n const response = toRegistrationResponse(input.response);\n\n const verification = await verifyRegistrationResponse({\n response,\n expectedChallenge: input.expectedChallenge,\n expectedOrigin: input.expectedOrigin,\n expectedRPID: input.expectedRpId,\n requireUserVerification: true,\n });\n\n if (!verification.verified) {\n return {\n verified: false,\n userVerified: false,\n };\n }\n\n const registration = verification.registrationInfo;\n const credential = registration.credential;\n\n return {\n verified: true,\n userVerified: registration.userVerified,\n credential: {\n credentialId: credential.id,\n publicKey: encodeBase64Url(credential.publicKey),\n counter: credential.counter,\n transports: credential.transports ?? [],\n },\n };\n }\n\n async generateAuthenticationOptions(input: {\n readonly challenge: string;\n readonly rpId: string;\n readonly allowCredentialIds?: readonly string[];\n readonly userVerification: \"required\";\n }): Promise<WebAuthnOptionsJSON> {\n validateChallenge(input.challenge);\n validateRpId(input.rpId);\n\n const allowCredentials = input.allowCredentialIds?.map((id) => {\n if (!id || !/^[A-Za-z0-9_-]+$/.test(id)) {\n throw new AuthValidationError(\n \"A stored passkey credential ID is invalid.\",\n );\n }\n\n return { id };\n });\n\n const options = await generateAuthenticationOptions({\n rpID: input.rpId,\n challenge: decodeBase64Url(\n input.challenge,\n \"A valid WebAuthn challenge is required.\",\n ),\n userVerification: \"required\",\n ...(allowCredentials\n ? {\n allowCredentials,\n }\n : {}),\n });\n\n if (options.challenge !== input.challenge) {\n throw new AuthConfigurationError(\n \"SimpleWebAuthn returned an unexpected authentication challenge.\",\n );\n }\n\n return options as unknown as WebAuthnOptionsJSON;\n }\n\n async verifyAuthenticationResponse(input: {\n readonly response: unknown;\n readonly expectedChallenge: string;\n readonly expectedOrigin: string;\n readonly expectedRpId: string;\n readonly credential: {\n readonly credentialId: string;\n readonly publicKey: string;\n readonly counter: number;\n readonly transports?: readonly string[];\n };\n }): Promise<WebAuthnAuthenticationVerification> {\n validateChallenge(input.expectedChallenge);\n validateRpId(input.expectedRpId);\n\n if (\n typeof input.expectedOrigin !== \"string\" ||\n input.expectedOrigin.length === 0\n ) {\n throw new AuthConfigurationError(\n \"A WebAuthn verification origin is required.\",\n );\n }\n\n const response = toAuthenticationResponse(input.response);\n\n if (response.id !== input.credential.credentialId) {\n return {\n verified: false,\n userVerified: false,\n credentialId: response.id,\n newCounter: input.credential.counter,\n };\n }\n\n if (\n !Number.isSafeInteger(input.credential.counter) ||\n input.credential.counter < 0\n ) {\n throw new AuthValidationError(\"The stored passkey counter is invalid.\");\n }\n\n const credential: WebAuthnCredential = {\n id: input.credential.credentialId,\n publicKey: decodeBase64Url(input.credential.publicKey),\n counter: input.credential.counter,\n };\n\n const verification = await verifyAuthenticationResponse({\n response,\n expectedChallenge: input.expectedChallenge,\n expectedOrigin: input.expectedOrigin,\n expectedRPID: input.expectedRpId,\n credential,\n requireUserVerification: true,\n });\n\n return {\n verified: verification.verified,\n userVerified:\n verification.verified && verification.authenticationInfo.userVerified,\n credentialId: verification.authenticationInfo.credentialID,\n newCounter: verification.authenticationInfo.newCounter,\n };\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { WebAuthnAuthenticationVerification, WebAuthnOptionsJSON, WebAuthnProvider, WebAuthnRegistrationVerification } from "./mfa-provider.types.cjs";
|
|
2
|
+
export declare class SimpleWebAuthnProvider implements WebAuthnProvider {
|
|
3
|
+
generateRegistrationOptions(input: {
|
|
4
|
+
readonly challenge: string;
|
|
5
|
+
readonly rpId: string;
|
|
6
|
+
readonly rpName: string;
|
|
7
|
+
readonly userId: string;
|
|
8
|
+
readonly userName: string;
|
|
9
|
+
readonly excludeCredentialIds: readonly string[];
|
|
10
|
+
}): Promise<WebAuthnOptionsJSON>;
|
|
11
|
+
verifyRegistrationResponse(input: {
|
|
12
|
+
readonly response: unknown;
|
|
13
|
+
readonly expectedChallenge: string;
|
|
14
|
+
readonly expectedOrigin: string;
|
|
15
|
+
readonly expectedRpId: string;
|
|
16
|
+
}): Promise<WebAuthnRegistrationVerification>;
|
|
17
|
+
generateAuthenticationOptions(input: {
|
|
18
|
+
readonly challenge: string;
|
|
19
|
+
readonly rpId: string;
|
|
20
|
+
readonly allowCredentialIds?: readonly string[];
|
|
21
|
+
readonly userVerification: "required";
|
|
22
|
+
}): Promise<WebAuthnOptionsJSON>;
|
|
23
|
+
verifyAuthenticationResponse(input: {
|
|
24
|
+
readonly response: unknown;
|
|
25
|
+
readonly expectedChallenge: string;
|
|
26
|
+
readonly expectedOrigin: string;
|
|
27
|
+
readonly expectedRpId: string;
|
|
28
|
+
readonly credential: {
|
|
29
|
+
readonly credentialId: string;
|
|
30
|
+
readonly publicKey: string;
|
|
31
|
+
readonly counter: number;
|
|
32
|
+
readonly transports?: readonly string[];
|
|
33
|
+
};
|
|
34
|
+
}): Promise<WebAuthnAuthenticationVerification>;
|
|
35
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { WebAuthnAuthenticationVerification, WebAuthnOptionsJSON, WebAuthnProvider, WebAuthnRegistrationVerification } from "./mfa-provider.types.js";
|
|
2
|
+
export declare class SimpleWebAuthnProvider implements WebAuthnProvider {
|
|
3
|
+
generateRegistrationOptions(input: {
|
|
4
|
+
readonly challenge: string;
|
|
5
|
+
readonly rpId: string;
|
|
6
|
+
readonly rpName: string;
|
|
7
|
+
readonly userId: string;
|
|
8
|
+
readonly userName: string;
|
|
9
|
+
readonly excludeCredentialIds: readonly string[];
|
|
10
|
+
}): Promise<WebAuthnOptionsJSON>;
|
|
11
|
+
verifyRegistrationResponse(input: {
|
|
12
|
+
readonly response: unknown;
|
|
13
|
+
readonly expectedChallenge: string;
|
|
14
|
+
readonly expectedOrigin: string;
|
|
15
|
+
readonly expectedRpId: string;
|
|
16
|
+
}): Promise<WebAuthnRegistrationVerification>;
|
|
17
|
+
generateAuthenticationOptions(input: {
|
|
18
|
+
readonly challenge: string;
|
|
19
|
+
readonly rpId: string;
|
|
20
|
+
readonly allowCredentialIds?: readonly string[];
|
|
21
|
+
readonly userVerification: "required";
|
|
22
|
+
}): Promise<WebAuthnOptionsJSON>;
|
|
23
|
+
verifyAuthenticationResponse(input: {
|
|
24
|
+
readonly response: unknown;
|
|
25
|
+
readonly expectedChallenge: string;
|
|
26
|
+
readonly expectedOrigin: string;
|
|
27
|
+
readonly expectedRpId: string;
|
|
28
|
+
readonly credential: {
|
|
29
|
+
readonly credentialId: string;
|
|
30
|
+
readonly publicKey: string;
|
|
31
|
+
readonly counter: number;
|
|
32
|
+
readonly transports?: readonly string[];
|
|
33
|
+
};
|
|
34
|
+
}): Promise<WebAuthnAuthenticationVerification>;
|
|
35
|
+
}
|