@metamask-previews/passkey-controller 0.0.0-preview-4c0846313
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/CHANGELOG.md +24 -0
- package/LICENSE +21 -0
- package/README.md +155 -0
- package/dist/PasskeyController.cjs +448 -0
- package/dist/PasskeyController.cjs.map +1 -0
- package/dist/PasskeyController.d.cts +168 -0
- package/dist/PasskeyController.d.cts.map +1 -0
- package/dist/PasskeyController.d.mts +168 -0
- package/dist/PasskeyController.d.mts.map +1 -0
- package/dist/PasskeyController.mjs +443 -0
- package/dist/PasskeyController.mjs.map +1 -0
- package/dist/ceremony-manager.cjs +134 -0
- package/dist/ceremony-manager.cjs.map +1 -0
- package/dist/ceremony-manager.d.cts +71 -0
- package/dist/ceremony-manager.d.cts.map +1 -0
- package/dist/ceremony-manager.d.mts +71 -0
- package/dist/ceremony-manager.d.mts.map +1 -0
- package/dist/ceremony-manager.mjs +130 -0
- package/dist/ceremony-manager.mjs.map +1 -0
- package/dist/constants.cjs +33 -0
- package/dist/constants.cjs.map +1 -0
- package/dist/constants.d.cts +30 -0
- package/dist/constants.d.cts.map +1 -0
- package/dist/constants.d.mts +30 -0
- package/dist/constants.d.mts.map +1 -0
- package/dist/constants.mjs +30 -0
- package/dist/constants.mjs.map +1 -0
- package/dist/errors.cjs +57 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.cts +34 -0
- package/dist/errors.d.cts.map +1 -0
- package/dist/errors.d.mts +34 -0
- package/dist/errors.d.mts.map +1 -0
- package/dist/errors.mjs +53 -0
- package/dist/errors.mjs.map +1 -0
- package/dist/index.cjs +19 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +9 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +9 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +5 -0
- package/dist/index.mjs.map +1 -0
- package/dist/key-derivation.cjs +76 -0
- package/dist/key-derivation.cjs.map +1 -0
- package/dist/key-derivation.d.cts +43 -0
- package/dist/key-derivation.d.cts.map +1 -0
- package/dist/key-derivation.d.mts +43 -0
- package/dist/key-derivation.d.mts.map +1 -0
- package/dist/key-derivation.mjs +71 -0
- package/dist/key-derivation.mjs.map +1 -0
- package/dist/logger.cjs +9 -0
- package/dist/logger.cjs.map +1 -0
- package/dist/logger.d.cts +5 -0
- package/dist/logger.d.cts.map +1 -0
- package/dist/logger.d.mts +5 -0
- package/dist/logger.d.mts.map +1 -0
- package/dist/logger.mjs +6 -0
- package/dist/logger.mjs.map +1 -0
- package/dist/types.cjs +3 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +92 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.mts +92 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +2 -0
- package/dist/types.mjs.map +1 -0
- package/dist/utils/crypto.cjs +55 -0
- package/dist/utils/crypto.cjs.map +1 -0
- package/dist/utils/crypto.d.cts +30 -0
- package/dist/utils/crypto.d.cts.map +1 -0
- package/dist/utils/crypto.d.mts +30 -0
- package/dist/utils/crypto.d.mts.map +1 -0
- package/dist/utils/crypto.mjs +49 -0
- package/dist/utils/crypto.mjs.map +1 -0
- package/dist/utils/encoding.cjs +42 -0
- package/dist/utils/encoding.cjs.map +1 -0
- package/dist/utils/encoding.d.cts +22 -0
- package/dist/utils/encoding.d.cts.map +1 -0
- package/dist/utils/encoding.d.mts +22 -0
- package/dist/utils/encoding.d.mts.map +1 -0
- package/dist/utils/encoding.mjs +36 -0
- package/dist/utils/encoding.mjs.map +1 -0
- package/dist/webauthn/constants.cjs +74 -0
- package/dist/webauthn/constants.cjs.map +1 -0
- package/dist/webauthn/constants.d.cts +68 -0
- package/dist/webauthn/constants.d.cts.map +1 -0
- package/dist/webauthn/constants.d.mts +68 -0
- package/dist/webauthn/constants.d.mts.map +1 -0
- package/dist/webauthn/constants.mjs +71 -0
- package/dist/webauthn/constants.mjs.map +1 -0
- package/dist/webauthn/decode-attestation-object.cjs +18 -0
- package/dist/webauthn/decode-attestation-object.cjs.map +1 -0
- package/dist/webauthn/decode-attestation-object.d.cts +10 -0
- package/dist/webauthn/decode-attestation-object.d.cts.map +1 -0
- package/dist/webauthn/decode-attestation-object.d.mts +10 -0
- package/dist/webauthn/decode-attestation-object.d.mts.map +1 -0
- package/dist/webauthn/decode-attestation-object.mjs +14 -0
- package/dist/webauthn/decode-attestation-object.mjs.map +1 -0
- package/dist/webauthn/decode-client-data-json.cjs +17 -0
- package/dist/webauthn/decode-client-data-json.cjs.map +1 -0
- package/dist/webauthn/decode-client-data-json.d.cts +9 -0
- package/dist/webauthn/decode-client-data-json.d.cts.map +1 -0
- package/dist/webauthn/decode-client-data-json.d.mts +9 -0
- package/dist/webauthn/decode-client-data-json.d.mts.map +1 -0
- package/dist/webauthn/decode-client-data-json.mjs +13 -0
- package/dist/webauthn/decode-client-data-json.mjs.map +1 -0
- package/dist/webauthn/match-expected-rp-id.cjs +43 -0
- package/dist/webauthn/match-expected-rp-id.cjs.map +1 -0
- package/dist/webauthn/match-expected-rp-id.d.cts +11 -0
- package/dist/webauthn/match-expected-rp-id.d.cts.map +1 -0
- package/dist/webauthn/match-expected-rp-id.d.mts +11 -0
- package/dist/webauthn/match-expected-rp-id.d.mts.map +1 -0
- package/dist/webauthn/match-expected-rp-id.mjs +39 -0
- package/dist/webauthn/match-expected-rp-id.mjs.map +1 -0
- package/dist/webauthn/parse-authenticator-data.cjs +69 -0
- package/dist/webauthn/parse-authenticator-data.cjs.map +1 -0
- package/dist/webauthn/parse-authenticator-data.d.cts +10 -0
- package/dist/webauthn/parse-authenticator-data.d.cts.map +1 -0
- package/dist/webauthn/parse-authenticator-data.d.mts +10 -0
- package/dist/webauthn/parse-authenticator-data.d.mts.map +1 -0
- package/dist/webauthn/parse-authenticator-data.mjs +65 -0
- package/dist/webauthn/parse-authenticator-data.mjs.map +1 -0
- package/dist/webauthn/types.cjs +3 -0
- package/dist/webauthn/types.cjs.map +1 -0
- package/dist/webauthn/types.d.cts +113 -0
- package/dist/webauthn/types.d.cts.map +1 -0
- package/dist/webauthn/types.d.mts +113 -0
- package/dist/webauthn/types.d.mts.map +1 -0
- package/dist/webauthn/types.mjs +2 -0
- package/dist/webauthn/types.mjs.map +1 -0
- package/dist/webauthn/verify-authentication-response.cjs +134 -0
- package/dist/webauthn/verify-authentication-response.cjs.map +1 -0
- package/dist/webauthn/verify-authentication-response.d.cts +63 -0
- package/dist/webauthn/verify-authentication-response.d.cts.map +1 -0
- package/dist/webauthn/verify-authentication-response.d.mts +63 -0
- package/dist/webauthn/verify-authentication-response.d.mts.map +1 -0
- package/dist/webauthn/verify-authentication-response.mjs +130 -0
- package/dist/webauthn/verify-authentication-response.mjs.map +1 -0
- package/dist/webauthn/verify-registration-response.cjs +205 -0
- package/dist/webauthn/verify-registration-response.cjs.map +1 -0
- package/dist/webauthn/verify-registration-response.d.cts +60 -0
- package/dist/webauthn/verify-registration-response.d.cts.map +1 -0
- package/dist/webauthn/verify-registration-response.d.mts +60 -0
- package/dist/webauthn/verify-registration-response.d.mts.map +1 -0
- package/dist/webauthn/verify-registration-response.mjs +201 -0
- package/dist/webauthn/verify-registration-response.mjs.map +1 -0
- package/dist/webauthn/verify-signature.cjs +176 -0
- package/dist/webauthn/verify-signature.cjs.map +1 -0
- package/dist/webauthn/verify-signature.d.cts +21 -0
- package/dist/webauthn/verify-signature.d.cts.map +1 -0
- package/dist/webauthn/verify-signature.d.mts +21 -0
- package/dist/webauthn/verify-signature.d.mts.map +1 -0
- package/dist/webauthn/verify-signature.mjs +172 -0
- package/dist/webauthn/verify-signature.mjs.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.cjs","sourceRoot":"","sources":["../../src/webauthn/types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n AuthenticatorTransportFuture,\n Base64URLString as Base64URL,\n} from '../types';\n\nexport type PublicKeyCredentialDescriptorJSON = {\n id: Base64URL;\n type: 'public-key';\n transports?: AuthenticatorTransportFuture[];\n};\n\nexport type PublicKeyCredentialHint =\n | 'hybrid'\n | 'security-key'\n | 'client-device';\n\nexport type PasskeyRegistrationOptions = {\n rp: { name: string; id: string };\n user: {\n id: Base64URL;\n name: string;\n displayName: string;\n };\n challenge: Base64URL;\n pubKeyCredParams: { alg: number; type: 'public-key' }[];\n timeout?: number;\n excludeCredentials?: PublicKeyCredentialDescriptorJSON[];\n authenticatorSelection?: {\n authenticatorAttachment?: 'cross-platform' | 'platform';\n residentKey?: 'discouraged' | 'preferred' | 'required';\n requireResidentKey?: boolean;\n userVerification?: 'discouraged' | 'preferred' | 'required';\n };\n hints?: PublicKeyCredentialHint[];\n attestation?: 'direct' | 'enterprise' | 'indirect' | 'none';\n extensions?: Record<string, unknown>;\n};\n\nexport type PasskeyRegistrationResponse = {\n id: Base64URL;\n rawId: Base64URL;\n type: 'public-key';\n response: {\n clientDataJSON: Base64URL;\n attestationObject: Base64URL;\n transports?: string[];\n publicKeyAlgorithm?: number;\n publicKey?: Base64URL;\n authenticatorData?: Base64URL;\n };\n authenticatorAttachment?: 'cross-platform' | 'platform';\n clientExtensionResults: Record<string, unknown>;\n};\n\nexport type PasskeyAuthenticationOptions = {\n challenge: Base64URL;\n timeout?: number;\n rpId?: string;\n allowCredentials?: PublicKeyCredentialDescriptorJSON[];\n userVerification?: 'discouraged' | 'preferred' | 'required';\n hints?: PublicKeyCredentialHint[];\n extensions?: Record<string, unknown>;\n};\n\nexport type PasskeyAuthenticationResponse = {\n id: Base64URL;\n rawId: Base64URL;\n type: 'public-key';\n response: {\n clientDataJSON: Base64URL;\n authenticatorData: Base64URL;\n signature: Base64URL;\n userHandle?: Base64URL;\n };\n authenticatorAttachment?: 'cross-platform' | 'platform';\n clientExtensionResults: Record<string, unknown>;\n};\n\nexport type ClientDataJSON = {\n type: string;\n challenge: string;\n origin: string;\n crossOrigin?: boolean;\n tokenBinding?: {\n id?: string;\n status: 'present' | 'supported' | 'not-supported';\n };\n};\n\nexport type AttestationFormat =\n | 'fido-u2f'\n | 'packed'\n | 'android-safetynet'\n | 'android-key'\n | 'tpm'\n | 'apple'\n | 'none';\n\nexport type AttestationObject = {\n get(key: 'fmt'): AttestationFormat;\n get(key: 'attStmt'): AttestationStatement;\n get(key: 'authData'): Uint8Array;\n};\n\nexport type AttestationStatement = {\n get(key: 'sig'): Uint8Array | undefined;\n get(key: 'x5c'): Uint8Array[] | undefined;\n get(key: 'alg'): number | undefined;\n readonly size: number;\n};\n\nexport type AuthenticatorDataFlags = {\n up: boolean;\n uv: boolean;\n be: boolean;\n bs: boolean;\n at: boolean;\n ed: boolean;\n flagsByte: number;\n};\n\nexport type ParsedAuthenticatorData = {\n rpIdHash: Uint8Array;\n flags: AuthenticatorDataFlags;\n counter: number;\n aaguid?: Uint8Array;\n credentialID?: Uint8Array;\n credentialPublicKey?: Uint8Array;\n extensionsData?: Map<string, unknown>;\n extensionsDataBuffer?: Uint8Array;\n};\n"]}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { AuthenticatorTransportFuture, Base64URLString as Base64URL } from "../types.cjs";
|
|
2
|
+
export type PublicKeyCredentialDescriptorJSON = {
|
|
3
|
+
id: Base64URL;
|
|
4
|
+
type: 'public-key';
|
|
5
|
+
transports?: AuthenticatorTransportFuture[];
|
|
6
|
+
};
|
|
7
|
+
export type PublicKeyCredentialHint = 'hybrid' | 'security-key' | 'client-device';
|
|
8
|
+
export type PasskeyRegistrationOptions = {
|
|
9
|
+
rp: {
|
|
10
|
+
name: string;
|
|
11
|
+
id: string;
|
|
12
|
+
};
|
|
13
|
+
user: {
|
|
14
|
+
id: Base64URL;
|
|
15
|
+
name: string;
|
|
16
|
+
displayName: string;
|
|
17
|
+
};
|
|
18
|
+
challenge: Base64URL;
|
|
19
|
+
pubKeyCredParams: {
|
|
20
|
+
alg: number;
|
|
21
|
+
type: 'public-key';
|
|
22
|
+
}[];
|
|
23
|
+
timeout?: number;
|
|
24
|
+
excludeCredentials?: PublicKeyCredentialDescriptorJSON[];
|
|
25
|
+
authenticatorSelection?: {
|
|
26
|
+
authenticatorAttachment?: 'cross-platform' | 'platform';
|
|
27
|
+
residentKey?: 'discouraged' | 'preferred' | 'required';
|
|
28
|
+
requireResidentKey?: boolean;
|
|
29
|
+
userVerification?: 'discouraged' | 'preferred' | 'required';
|
|
30
|
+
};
|
|
31
|
+
hints?: PublicKeyCredentialHint[];
|
|
32
|
+
attestation?: 'direct' | 'enterprise' | 'indirect' | 'none';
|
|
33
|
+
extensions?: Record<string, unknown>;
|
|
34
|
+
};
|
|
35
|
+
export type PasskeyRegistrationResponse = {
|
|
36
|
+
id: Base64URL;
|
|
37
|
+
rawId: Base64URL;
|
|
38
|
+
type: 'public-key';
|
|
39
|
+
response: {
|
|
40
|
+
clientDataJSON: Base64URL;
|
|
41
|
+
attestationObject: Base64URL;
|
|
42
|
+
transports?: string[];
|
|
43
|
+
publicKeyAlgorithm?: number;
|
|
44
|
+
publicKey?: Base64URL;
|
|
45
|
+
authenticatorData?: Base64URL;
|
|
46
|
+
};
|
|
47
|
+
authenticatorAttachment?: 'cross-platform' | 'platform';
|
|
48
|
+
clientExtensionResults: Record<string, unknown>;
|
|
49
|
+
};
|
|
50
|
+
export type PasskeyAuthenticationOptions = {
|
|
51
|
+
challenge: Base64URL;
|
|
52
|
+
timeout?: number;
|
|
53
|
+
rpId?: string;
|
|
54
|
+
allowCredentials?: PublicKeyCredentialDescriptorJSON[];
|
|
55
|
+
userVerification?: 'discouraged' | 'preferred' | 'required';
|
|
56
|
+
hints?: PublicKeyCredentialHint[];
|
|
57
|
+
extensions?: Record<string, unknown>;
|
|
58
|
+
};
|
|
59
|
+
export type PasskeyAuthenticationResponse = {
|
|
60
|
+
id: Base64URL;
|
|
61
|
+
rawId: Base64URL;
|
|
62
|
+
type: 'public-key';
|
|
63
|
+
response: {
|
|
64
|
+
clientDataJSON: Base64URL;
|
|
65
|
+
authenticatorData: Base64URL;
|
|
66
|
+
signature: Base64URL;
|
|
67
|
+
userHandle?: Base64URL;
|
|
68
|
+
};
|
|
69
|
+
authenticatorAttachment?: 'cross-platform' | 'platform';
|
|
70
|
+
clientExtensionResults: Record<string, unknown>;
|
|
71
|
+
};
|
|
72
|
+
export type ClientDataJSON = {
|
|
73
|
+
type: string;
|
|
74
|
+
challenge: string;
|
|
75
|
+
origin: string;
|
|
76
|
+
crossOrigin?: boolean;
|
|
77
|
+
tokenBinding?: {
|
|
78
|
+
id?: string;
|
|
79
|
+
status: 'present' | 'supported' | 'not-supported';
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
export type AttestationFormat = 'fido-u2f' | 'packed' | 'android-safetynet' | 'android-key' | 'tpm' | 'apple' | 'none';
|
|
83
|
+
export type AttestationObject = {
|
|
84
|
+
get(key: 'fmt'): AttestationFormat;
|
|
85
|
+
get(key: 'attStmt'): AttestationStatement;
|
|
86
|
+
get(key: 'authData'): Uint8Array;
|
|
87
|
+
};
|
|
88
|
+
export type AttestationStatement = {
|
|
89
|
+
get(key: 'sig'): Uint8Array | undefined;
|
|
90
|
+
get(key: 'x5c'): Uint8Array[] | undefined;
|
|
91
|
+
get(key: 'alg'): number | undefined;
|
|
92
|
+
readonly size: number;
|
|
93
|
+
};
|
|
94
|
+
export type AuthenticatorDataFlags = {
|
|
95
|
+
up: boolean;
|
|
96
|
+
uv: boolean;
|
|
97
|
+
be: boolean;
|
|
98
|
+
bs: boolean;
|
|
99
|
+
at: boolean;
|
|
100
|
+
ed: boolean;
|
|
101
|
+
flagsByte: number;
|
|
102
|
+
};
|
|
103
|
+
export type ParsedAuthenticatorData = {
|
|
104
|
+
rpIdHash: Uint8Array;
|
|
105
|
+
flags: AuthenticatorDataFlags;
|
|
106
|
+
counter: number;
|
|
107
|
+
aaguid?: Uint8Array;
|
|
108
|
+
credentialID?: Uint8Array;
|
|
109
|
+
credentialPublicKey?: Uint8Array;
|
|
110
|
+
extensionsData?: Map<string, unknown>;
|
|
111
|
+
extensionsDataBuffer?: Uint8Array;
|
|
112
|
+
};
|
|
113
|
+
//# sourceMappingURL=types.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.cts","sourceRoot":"","sources":["../../src/webauthn/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { AuthenticatorTransportFuture, Base64URLString as Base64URL } from "../types.mjs";
|
|
2
|
+
export type PublicKeyCredentialDescriptorJSON = {
|
|
3
|
+
id: Base64URL;
|
|
4
|
+
type: 'public-key';
|
|
5
|
+
transports?: AuthenticatorTransportFuture[];
|
|
6
|
+
};
|
|
7
|
+
export type PublicKeyCredentialHint = 'hybrid' | 'security-key' | 'client-device';
|
|
8
|
+
export type PasskeyRegistrationOptions = {
|
|
9
|
+
rp: {
|
|
10
|
+
name: string;
|
|
11
|
+
id: string;
|
|
12
|
+
};
|
|
13
|
+
user: {
|
|
14
|
+
id: Base64URL;
|
|
15
|
+
name: string;
|
|
16
|
+
displayName: string;
|
|
17
|
+
};
|
|
18
|
+
challenge: Base64URL;
|
|
19
|
+
pubKeyCredParams: {
|
|
20
|
+
alg: number;
|
|
21
|
+
type: 'public-key';
|
|
22
|
+
}[];
|
|
23
|
+
timeout?: number;
|
|
24
|
+
excludeCredentials?: PublicKeyCredentialDescriptorJSON[];
|
|
25
|
+
authenticatorSelection?: {
|
|
26
|
+
authenticatorAttachment?: 'cross-platform' | 'platform';
|
|
27
|
+
residentKey?: 'discouraged' | 'preferred' | 'required';
|
|
28
|
+
requireResidentKey?: boolean;
|
|
29
|
+
userVerification?: 'discouraged' | 'preferred' | 'required';
|
|
30
|
+
};
|
|
31
|
+
hints?: PublicKeyCredentialHint[];
|
|
32
|
+
attestation?: 'direct' | 'enterprise' | 'indirect' | 'none';
|
|
33
|
+
extensions?: Record<string, unknown>;
|
|
34
|
+
};
|
|
35
|
+
export type PasskeyRegistrationResponse = {
|
|
36
|
+
id: Base64URL;
|
|
37
|
+
rawId: Base64URL;
|
|
38
|
+
type: 'public-key';
|
|
39
|
+
response: {
|
|
40
|
+
clientDataJSON: Base64URL;
|
|
41
|
+
attestationObject: Base64URL;
|
|
42
|
+
transports?: string[];
|
|
43
|
+
publicKeyAlgorithm?: number;
|
|
44
|
+
publicKey?: Base64URL;
|
|
45
|
+
authenticatorData?: Base64URL;
|
|
46
|
+
};
|
|
47
|
+
authenticatorAttachment?: 'cross-platform' | 'platform';
|
|
48
|
+
clientExtensionResults: Record<string, unknown>;
|
|
49
|
+
};
|
|
50
|
+
export type PasskeyAuthenticationOptions = {
|
|
51
|
+
challenge: Base64URL;
|
|
52
|
+
timeout?: number;
|
|
53
|
+
rpId?: string;
|
|
54
|
+
allowCredentials?: PublicKeyCredentialDescriptorJSON[];
|
|
55
|
+
userVerification?: 'discouraged' | 'preferred' | 'required';
|
|
56
|
+
hints?: PublicKeyCredentialHint[];
|
|
57
|
+
extensions?: Record<string, unknown>;
|
|
58
|
+
};
|
|
59
|
+
export type PasskeyAuthenticationResponse = {
|
|
60
|
+
id: Base64URL;
|
|
61
|
+
rawId: Base64URL;
|
|
62
|
+
type: 'public-key';
|
|
63
|
+
response: {
|
|
64
|
+
clientDataJSON: Base64URL;
|
|
65
|
+
authenticatorData: Base64URL;
|
|
66
|
+
signature: Base64URL;
|
|
67
|
+
userHandle?: Base64URL;
|
|
68
|
+
};
|
|
69
|
+
authenticatorAttachment?: 'cross-platform' | 'platform';
|
|
70
|
+
clientExtensionResults: Record<string, unknown>;
|
|
71
|
+
};
|
|
72
|
+
export type ClientDataJSON = {
|
|
73
|
+
type: string;
|
|
74
|
+
challenge: string;
|
|
75
|
+
origin: string;
|
|
76
|
+
crossOrigin?: boolean;
|
|
77
|
+
tokenBinding?: {
|
|
78
|
+
id?: string;
|
|
79
|
+
status: 'present' | 'supported' | 'not-supported';
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
export type AttestationFormat = 'fido-u2f' | 'packed' | 'android-safetynet' | 'android-key' | 'tpm' | 'apple' | 'none';
|
|
83
|
+
export type AttestationObject = {
|
|
84
|
+
get(key: 'fmt'): AttestationFormat;
|
|
85
|
+
get(key: 'attStmt'): AttestationStatement;
|
|
86
|
+
get(key: 'authData'): Uint8Array;
|
|
87
|
+
};
|
|
88
|
+
export type AttestationStatement = {
|
|
89
|
+
get(key: 'sig'): Uint8Array | undefined;
|
|
90
|
+
get(key: 'x5c'): Uint8Array[] | undefined;
|
|
91
|
+
get(key: 'alg'): number | undefined;
|
|
92
|
+
readonly size: number;
|
|
93
|
+
};
|
|
94
|
+
export type AuthenticatorDataFlags = {
|
|
95
|
+
up: boolean;
|
|
96
|
+
uv: boolean;
|
|
97
|
+
be: boolean;
|
|
98
|
+
bs: boolean;
|
|
99
|
+
at: boolean;
|
|
100
|
+
ed: boolean;
|
|
101
|
+
flagsByte: number;
|
|
102
|
+
};
|
|
103
|
+
export type ParsedAuthenticatorData = {
|
|
104
|
+
rpIdHash: Uint8Array;
|
|
105
|
+
flags: AuthenticatorDataFlags;
|
|
106
|
+
counter: number;
|
|
107
|
+
aaguid?: Uint8Array;
|
|
108
|
+
credentialID?: Uint8Array;
|
|
109
|
+
credentialPublicKey?: Uint8Array;
|
|
110
|
+
extensionsData?: Map<string, unknown>;
|
|
111
|
+
extensionsDataBuffer?: Uint8Array;
|
|
112
|
+
};
|
|
113
|
+
//# sourceMappingURL=types.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../../src/webauthn/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.mjs","sourceRoot":"","sources":["../../src/webauthn/types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n AuthenticatorTransportFuture,\n Base64URLString as Base64URL,\n} from '../types';\n\nexport type PublicKeyCredentialDescriptorJSON = {\n id: Base64URL;\n type: 'public-key';\n transports?: AuthenticatorTransportFuture[];\n};\n\nexport type PublicKeyCredentialHint =\n | 'hybrid'\n | 'security-key'\n | 'client-device';\n\nexport type PasskeyRegistrationOptions = {\n rp: { name: string; id: string };\n user: {\n id: Base64URL;\n name: string;\n displayName: string;\n };\n challenge: Base64URL;\n pubKeyCredParams: { alg: number; type: 'public-key' }[];\n timeout?: number;\n excludeCredentials?: PublicKeyCredentialDescriptorJSON[];\n authenticatorSelection?: {\n authenticatorAttachment?: 'cross-platform' | 'platform';\n residentKey?: 'discouraged' | 'preferred' | 'required';\n requireResidentKey?: boolean;\n userVerification?: 'discouraged' | 'preferred' | 'required';\n };\n hints?: PublicKeyCredentialHint[];\n attestation?: 'direct' | 'enterprise' | 'indirect' | 'none';\n extensions?: Record<string, unknown>;\n};\n\nexport type PasskeyRegistrationResponse = {\n id: Base64URL;\n rawId: Base64URL;\n type: 'public-key';\n response: {\n clientDataJSON: Base64URL;\n attestationObject: Base64URL;\n transports?: string[];\n publicKeyAlgorithm?: number;\n publicKey?: Base64URL;\n authenticatorData?: Base64URL;\n };\n authenticatorAttachment?: 'cross-platform' | 'platform';\n clientExtensionResults: Record<string, unknown>;\n};\n\nexport type PasskeyAuthenticationOptions = {\n challenge: Base64URL;\n timeout?: number;\n rpId?: string;\n allowCredentials?: PublicKeyCredentialDescriptorJSON[];\n userVerification?: 'discouraged' | 'preferred' | 'required';\n hints?: PublicKeyCredentialHint[];\n extensions?: Record<string, unknown>;\n};\n\nexport type PasskeyAuthenticationResponse = {\n id: Base64URL;\n rawId: Base64URL;\n type: 'public-key';\n response: {\n clientDataJSON: Base64URL;\n authenticatorData: Base64URL;\n signature: Base64URL;\n userHandle?: Base64URL;\n };\n authenticatorAttachment?: 'cross-platform' | 'platform';\n clientExtensionResults: Record<string, unknown>;\n};\n\nexport type ClientDataJSON = {\n type: string;\n challenge: string;\n origin: string;\n crossOrigin?: boolean;\n tokenBinding?: {\n id?: string;\n status: 'present' | 'supported' | 'not-supported';\n };\n};\n\nexport type AttestationFormat =\n | 'fido-u2f'\n | 'packed'\n | 'android-safetynet'\n | 'android-key'\n | 'tpm'\n | 'apple'\n | 'none';\n\nexport type AttestationObject = {\n get(key: 'fmt'): AttestationFormat;\n get(key: 'attStmt'): AttestationStatement;\n get(key: 'authData'): Uint8Array;\n};\n\nexport type AttestationStatement = {\n get(key: 'sig'): Uint8Array | undefined;\n get(key: 'x5c'): Uint8Array[] | undefined;\n get(key: 'alg'): number | undefined;\n readonly size: number;\n};\n\nexport type AuthenticatorDataFlags = {\n up: boolean;\n uv: boolean;\n be: boolean;\n bs: boolean;\n at: boolean;\n ed: boolean;\n flagsByte: number;\n};\n\nexport type ParsedAuthenticatorData = {\n rpIdHash: Uint8Array;\n flags: AuthenticatorDataFlags;\n counter: number;\n aaguid?: Uint8Array;\n credentialID?: Uint8Array;\n credentialPublicKey?: Uint8Array;\n extensionsData?: Map<string, unknown>;\n extensionsDataBuffer?: Uint8Array;\n};\n"]}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.verifyAuthenticationResponse = void 0;
|
|
4
|
+
const tiny_cbor_1 = require("@levischuck/tiny-cbor");
|
|
5
|
+
const utils_1 = require("@metamask/utils");
|
|
6
|
+
const sha2_1 = require("@noble/hashes/sha2");
|
|
7
|
+
const encoding_1 = require("../utils/encoding.cjs");
|
|
8
|
+
const decode_client_data_json_1 = require("./decode-client-data-json.cjs");
|
|
9
|
+
const match_expected_rp_id_1 = require("./match-expected-rp-id.cjs");
|
|
10
|
+
const parse_authenticator_data_1 = require("./parse-authenticator-data.cjs");
|
|
11
|
+
const verify_signature_1 = require("./verify-signature.cjs");
|
|
12
|
+
/**
|
|
13
|
+
* Verifies a WebAuthn authentication (assertion) response per
|
|
14
|
+
* W3C WebAuthn Level 3 §7.2.
|
|
15
|
+
*
|
|
16
|
+
* Performs the following checks in order:
|
|
17
|
+
* 1. Credential ID presence, base64url consistency, and type.
|
|
18
|
+
* 2. `clientDataJSON` -- type is `"webauthn.get"`, challenge and origin
|
|
19
|
+
* match.
|
|
20
|
+
* 3. `authenticatorData` -- RP ID hash matches, user-presence flag is
|
|
21
|
+
* set, and optional user-verification flag is checked.
|
|
22
|
+
* 4. Signature verification -- `signature` is verified over
|
|
23
|
+
* `authData || SHA-256(clientDataJSON)` using the stored credential
|
|
24
|
+
* public key (COSE-encoded).
|
|
25
|
+
* 5. Counter monotonicity -- if either the stored or returned counter
|
|
26
|
+
* is non-zero, the new counter must exceed the stored value.
|
|
27
|
+
*
|
|
28
|
+
* @param opts - Verification options.
|
|
29
|
+
* @param opts.response - The `PublicKeyCredential` result from
|
|
30
|
+
* `navigator.credentials.get()`, serialized as JSON.
|
|
31
|
+
* @param opts.expectedChallenge - The base64url challenge that was issued
|
|
32
|
+
* for this ceremony.
|
|
33
|
+
* @param opts.expectedOrigin - One or more acceptable origins.
|
|
34
|
+
* @param opts.expectedRPID - The Relying Party ID domain.
|
|
35
|
+
* @param opts.credential - The stored credential record to verify against.
|
|
36
|
+
* @param opts.credential.id - The credential ID (base64url).
|
|
37
|
+
* @param opts.credential.publicKey - The COSE-encoded public key bytes
|
|
38
|
+
* persisted during registration.
|
|
39
|
+
* @param opts.credential.counter - The last known signature counter value.
|
|
40
|
+
* @param opts.credential.transports - Optional authenticator transports.
|
|
41
|
+
* @param opts.requireUserVerification - When `true`, verification fails
|
|
42
|
+
* if the UV flag is not set. Defaults to `false`.
|
|
43
|
+
* @returns Verification result containing `verified` status and parsed
|
|
44
|
+
* authentication info (new counter, origin, RP ID).
|
|
45
|
+
*/
|
|
46
|
+
async function verifyAuthenticationResponse(opts) {
|
|
47
|
+
const { response, expectedChallenge, expectedOrigin, expectedRPID, credential, requireUserVerification = false, } = opts;
|
|
48
|
+
const { id, rawId, type: credentialType, response: assertionResponse, } = response;
|
|
49
|
+
// Ensure credential specified an ID
|
|
50
|
+
if (!id) {
|
|
51
|
+
throw new Error('Missing credential ID');
|
|
52
|
+
}
|
|
53
|
+
// Ensure ID is base64url-encoded
|
|
54
|
+
if (id !== rawId) {
|
|
55
|
+
throw new Error('Credential ID was not base64url-encoded');
|
|
56
|
+
}
|
|
57
|
+
// Make sure credential type is public-key
|
|
58
|
+
if (credentialType !== 'public-key') {
|
|
59
|
+
throw new Error(`Unexpected credential type ${String(credentialType)}, expected "public-key"`);
|
|
60
|
+
}
|
|
61
|
+
if (typeof assertionResponse?.clientDataJSON !== 'string') {
|
|
62
|
+
throw new Error('Credential response clientDataJSON was not a string');
|
|
63
|
+
}
|
|
64
|
+
const clientDataJSON = (0, decode_client_data_json_1.decodeClientDataJSON)(assertionResponse.clientDataJSON);
|
|
65
|
+
const { type, challenge, origin, tokenBinding } = clientDataJSON;
|
|
66
|
+
// Make sure we're handling an authentication
|
|
67
|
+
if (type !== 'webauthn.get') {
|
|
68
|
+
throw new Error(`Unexpected authentication response type: ${type}`);
|
|
69
|
+
}
|
|
70
|
+
// Ensure the device provided the challenge we gave it
|
|
71
|
+
if (challenge !== expectedChallenge) {
|
|
72
|
+
throw new Error(`Unexpected authentication response challenge "${challenge}", expected "${expectedChallenge}"`);
|
|
73
|
+
}
|
|
74
|
+
// Check that the origin is our site
|
|
75
|
+
const expectedOrigins = Array.isArray(expectedOrigin)
|
|
76
|
+
? expectedOrigin
|
|
77
|
+
: [expectedOrigin];
|
|
78
|
+
if (!expectedOrigins.includes(origin)) {
|
|
79
|
+
throw new Error(`Unexpected authentication response origin "${origin}", expected one of: ${expectedOrigins.join(', ')}`);
|
|
80
|
+
}
|
|
81
|
+
if (assertionResponse.userHandle &&
|
|
82
|
+
typeof assertionResponse.userHandle !== 'string') {
|
|
83
|
+
throw new Error('Credential response userHandle was not a string');
|
|
84
|
+
}
|
|
85
|
+
if (tokenBinding) {
|
|
86
|
+
if (typeof tokenBinding !== 'object') {
|
|
87
|
+
throw new Error('ClientDataJSON tokenBinding was not an object');
|
|
88
|
+
}
|
|
89
|
+
if (!['present', 'supported', 'not-supported'].includes(tokenBinding.status)) {
|
|
90
|
+
throw new Error(`Unexpected tokenBinding status ${tokenBinding.status}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const authDataBuffer = (0, encoding_1.base64URLToBytes)(assertionResponse.authenticatorData);
|
|
94
|
+
const parsedAuthData = (0, parse_authenticator_data_1.parseAuthenticatorData)(authDataBuffer);
|
|
95
|
+
const { rpIdHash, flags, counter } = parsedAuthData;
|
|
96
|
+
// Make sure the response's RP ID is ours
|
|
97
|
+
const matchedRPID = (0, match_expected_rp_id_1.matchExpectedRPID)(rpIdHash, [expectedRPID]);
|
|
98
|
+
// WebAuthn only requires the user presence flag be true
|
|
99
|
+
if (!flags.up) {
|
|
100
|
+
throw new Error('User not present during authentication');
|
|
101
|
+
}
|
|
102
|
+
// Enforce user verification if required
|
|
103
|
+
if (requireUserVerification && !flags.uv) {
|
|
104
|
+
throw new Error('User verification required, but user could not be verified');
|
|
105
|
+
}
|
|
106
|
+
const clientDataHash = (0, sha2_1.sha256)((0, encoding_1.base64URLToBytes)(assertionResponse.clientDataJSON));
|
|
107
|
+
const signatureBase = (0, utils_1.concatBytes)([authDataBuffer, clientDataHash]);
|
|
108
|
+
const signature = (0, encoding_1.base64URLToBytes)(assertionResponse.signature);
|
|
109
|
+
const cosePublicKey = (0, tiny_cbor_1.decodePartialCBOR)(new Uint8Array(credential.publicKey), 0)[0];
|
|
110
|
+
const verified = await (0, verify_signature_1.verifySignature)({
|
|
111
|
+
cosePublicKey,
|
|
112
|
+
signature,
|
|
113
|
+
data: signatureBase,
|
|
114
|
+
});
|
|
115
|
+
if (!verified) {
|
|
116
|
+
return { verified: false };
|
|
117
|
+
}
|
|
118
|
+
if ((counter > 0 || credential.counter > 0) &&
|
|
119
|
+
counter <= credential.counter) {
|
|
120
|
+
throw new Error(`Response counter value ${counter} was lower than expected ${credential.counter}`);
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
verified: true,
|
|
124
|
+
authenticationInfo: {
|
|
125
|
+
credentialId: credential.id,
|
|
126
|
+
newCounter: counter,
|
|
127
|
+
userVerified: flags.uv,
|
|
128
|
+
origin: clientDataJSON.origin,
|
|
129
|
+
rpID: matchedRPID,
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
exports.verifyAuthenticationResponse = verifyAuthenticationResponse;
|
|
134
|
+
//# sourceMappingURL=verify-authentication-response.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-authentication-response.cjs","sourceRoot":"","sources":["../../src/webauthn/verify-authentication-response.ts"],"names":[],"mappings":"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","sourcesContent":["import { decodePartialCBOR } from '@levischuck/tiny-cbor';\nimport { concatBytes } from '@metamask/utils';\nimport { sha256 } from '@noble/hashes/sha2';\n\nimport type { AuthenticatorTransportFuture } from '../types';\nimport { base64URLToBytes } from '../utils/encoding';\nimport { decodeClientDataJSON } from './decode-client-data-json';\nimport { matchExpectedRPID } from './match-expected-rp-id';\nimport { parseAuthenticatorData } from './parse-authenticator-data';\nimport type { ParsedAuthenticatorData } from './types';\nimport type { PasskeyAuthenticationResponse } from './types';\nimport { verifySignature } from './verify-signature';\n\nexport type VerifiedAuthenticationResponse =\n | { verified: false; authenticationInfo?: never }\n | {\n verified: true;\n authenticationInfo: {\n credentialId: string;\n newCounter: number;\n userVerified: boolean;\n origin: string;\n rpID: string;\n };\n };\n\n/**\n * Verifies a WebAuthn authentication (assertion) response per\n * W3C WebAuthn Level 3 §7.2.\n *\n * Performs the following checks in order:\n * 1. Credential ID presence, base64url consistency, and type.\n * 2. `clientDataJSON` -- type is `\"webauthn.get\"`, challenge and origin\n * match.\n * 3. `authenticatorData` -- RP ID hash matches, user-presence flag is\n * set, and optional user-verification flag is checked.\n * 4. Signature verification -- `signature` is verified over\n * `authData || SHA-256(clientDataJSON)` using the stored credential\n * public key (COSE-encoded).\n * 5. Counter monotonicity -- if either the stored or returned counter\n * is non-zero, the new counter must exceed the stored value.\n *\n * @param opts - Verification options.\n * @param opts.response - The `PublicKeyCredential` result from\n * `navigator.credentials.get()`, serialized as JSON.\n * @param opts.expectedChallenge - The base64url challenge that was issued\n * for this ceremony.\n * @param opts.expectedOrigin - One or more acceptable origins.\n * @param opts.expectedRPID - The Relying Party ID domain.\n * @param opts.credential - The stored credential record to verify against.\n * @param opts.credential.id - The credential ID (base64url).\n * @param opts.credential.publicKey - The COSE-encoded public key bytes\n * persisted during registration.\n * @param opts.credential.counter - The last known signature counter value.\n * @param opts.credential.transports - Optional authenticator transports.\n * @param opts.requireUserVerification - When `true`, verification fails\n * if the UV flag is not set. Defaults to `false`.\n * @returns Verification result containing `verified` status and parsed\n * authentication info (new counter, origin, RP ID).\n */\nexport async function verifyAuthenticationResponse(opts: {\n response: PasskeyAuthenticationResponse;\n expectedChallenge: string;\n expectedOrigin: string | string[];\n expectedRPID: string;\n credential: {\n id: string;\n publicKey: Uint8Array;\n counter: number;\n transports?: AuthenticatorTransportFuture[];\n };\n requireUserVerification?: boolean;\n}): Promise<VerifiedAuthenticationResponse> {\n const {\n response,\n expectedChallenge,\n expectedOrigin,\n expectedRPID,\n credential,\n requireUserVerification = false,\n } = opts;\n\n const {\n id,\n rawId,\n type: credentialType,\n response: assertionResponse,\n } = response;\n\n // Ensure credential specified an ID\n if (!id) {\n throw new Error('Missing credential ID');\n }\n\n // Ensure ID is base64url-encoded\n if (id !== rawId) {\n throw new Error('Credential ID was not base64url-encoded');\n }\n\n // Make sure credential type is public-key\n if (credentialType !== 'public-key') {\n throw new Error(\n `Unexpected credential type ${String(credentialType)}, expected \"public-key\"`,\n );\n }\n\n if (typeof assertionResponse?.clientDataJSON !== 'string') {\n throw new Error('Credential response clientDataJSON was not a string');\n }\n\n const clientDataJSON = decodeClientDataJSON(assertionResponse.clientDataJSON);\n const { type, challenge, origin, tokenBinding } = clientDataJSON;\n\n // Make sure we're handling an authentication\n if (type !== 'webauthn.get') {\n throw new Error(`Unexpected authentication response type: ${type}`);\n }\n\n // Ensure the device provided the challenge we gave it\n if (challenge !== expectedChallenge) {\n throw new Error(\n `Unexpected authentication response challenge \"${challenge}\", expected \"${expectedChallenge}\"`,\n );\n }\n\n // Check that the origin is our site\n const expectedOrigins = Array.isArray(expectedOrigin)\n ? expectedOrigin\n : [expectedOrigin];\n if (!expectedOrigins.includes(origin)) {\n throw new Error(\n `Unexpected authentication response origin \"${origin}\", expected one of: ${expectedOrigins.join(', ')}`,\n );\n }\n\n if (\n assertionResponse.userHandle &&\n typeof assertionResponse.userHandle !== 'string'\n ) {\n throw new Error('Credential response userHandle was not a string');\n }\n\n if (tokenBinding) {\n if (typeof tokenBinding !== 'object') {\n throw new Error('ClientDataJSON tokenBinding was not an object');\n }\n\n if (\n !['present', 'supported', 'not-supported'].includes(tokenBinding.status)\n ) {\n throw new Error(`Unexpected tokenBinding status ${tokenBinding.status}`);\n }\n }\n\n const authDataBuffer = base64URLToBytes(assertionResponse.authenticatorData);\n const parsedAuthData: ParsedAuthenticatorData =\n parseAuthenticatorData(authDataBuffer);\n const { rpIdHash, flags, counter } = parsedAuthData;\n\n // Make sure the response's RP ID is ours\n const matchedRPID = matchExpectedRPID(rpIdHash, [expectedRPID]);\n\n // WebAuthn only requires the user presence flag be true\n if (!flags.up) {\n throw new Error('User not present during authentication');\n }\n\n // Enforce user verification if required\n if (requireUserVerification && !flags.uv) {\n throw new Error(\n 'User verification required, but user could not be verified',\n );\n }\n\n const clientDataHash = sha256(\n base64URLToBytes(assertionResponse.clientDataJSON),\n );\n const signatureBase = concatBytes([authDataBuffer, clientDataHash]);\n\n const signature = base64URLToBytes(assertionResponse.signature);\n\n const cosePublicKey = decodePartialCBOR(\n new Uint8Array(credential.publicKey),\n 0,\n )[0] as Map<number, number | Uint8Array>;\n\n const verified = await verifySignature({\n cosePublicKey,\n signature,\n data: signatureBase,\n });\n\n if (!verified) {\n return { verified: false };\n }\n\n if (\n (counter > 0 || credential.counter > 0) &&\n counter <= credential.counter\n ) {\n throw new Error(\n `Response counter value ${counter} was lower than expected ${credential.counter}`,\n );\n }\n\n return {\n verified: true,\n authenticationInfo: {\n credentialId: credential.id,\n newCounter: counter,\n userVerified: flags.uv,\n origin: clientDataJSON.origin,\n rpID: matchedRPID,\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { AuthenticatorTransportFuture } from "../types.cjs";
|
|
2
|
+
import type { PasskeyAuthenticationResponse } from "./types.cjs";
|
|
3
|
+
export type VerifiedAuthenticationResponse = {
|
|
4
|
+
verified: false;
|
|
5
|
+
authenticationInfo?: never;
|
|
6
|
+
} | {
|
|
7
|
+
verified: true;
|
|
8
|
+
authenticationInfo: {
|
|
9
|
+
credentialId: string;
|
|
10
|
+
newCounter: number;
|
|
11
|
+
userVerified: boolean;
|
|
12
|
+
origin: string;
|
|
13
|
+
rpID: string;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Verifies a WebAuthn authentication (assertion) response per
|
|
18
|
+
* W3C WebAuthn Level 3 §7.2.
|
|
19
|
+
*
|
|
20
|
+
* Performs the following checks in order:
|
|
21
|
+
* 1. Credential ID presence, base64url consistency, and type.
|
|
22
|
+
* 2. `clientDataJSON` -- type is `"webauthn.get"`, challenge and origin
|
|
23
|
+
* match.
|
|
24
|
+
* 3. `authenticatorData` -- RP ID hash matches, user-presence flag is
|
|
25
|
+
* set, and optional user-verification flag is checked.
|
|
26
|
+
* 4. Signature verification -- `signature` is verified over
|
|
27
|
+
* `authData || SHA-256(clientDataJSON)` using the stored credential
|
|
28
|
+
* public key (COSE-encoded).
|
|
29
|
+
* 5. Counter monotonicity -- if either the stored or returned counter
|
|
30
|
+
* is non-zero, the new counter must exceed the stored value.
|
|
31
|
+
*
|
|
32
|
+
* @param opts - Verification options.
|
|
33
|
+
* @param opts.response - The `PublicKeyCredential` result from
|
|
34
|
+
* `navigator.credentials.get()`, serialized as JSON.
|
|
35
|
+
* @param opts.expectedChallenge - The base64url challenge that was issued
|
|
36
|
+
* for this ceremony.
|
|
37
|
+
* @param opts.expectedOrigin - One or more acceptable origins.
|
|
38
|
+
* @param opts.expectedRPID - The Relying Party ID domain.
|
|
39
|
+
* @param opts.credential - The stored credential record to verify against.
|
|
40
|
+
* @param opts.credential.id - The credential ID (base64url).
|
|
41
|
+
* @param opts.credential.publicKey - The COSE-encoded public key bytes
|
|
42
|
+
* persisted during registration.
|
|
43
|
+
* @param opts.credential.counter - The last known signature counter value.
|
|
44
|
+
* @param opts.credential.transports - Optional authenticator transports.
|
|
45
|
+
* @param opts.requireUserVerification - When `true`, verification fails
|
|
46
|
+
* if the UV flag is not set. Defaults to `false`.
|
|
47
|
+
* @returns Verification result containing `verified` status and parsed
|
|
48
|
+
* authentication info (new counter, origin, RP ID).
|
|
49
|
+
*/
|
|
50
|
+
export declare function verifyAuthenticationResponse(opts: {
|
|
51
|
+
response: PasskeyAuthenticationResponse;
|
|
52
|
+
expectedChallenge: string;
|
|
53
|
+
expectedOrigin: string | string[];
|
|
54
|
+
expectedRPID: string;
|
|
55
|
+
credential: {
|
|
56
|
+
id: string;
|
|
57
|
+
publicKey: Uint8Array;
|
|
58
|
+
counter: number;
|
|
59
|
+
transports?: AuthenticatorTransportFuture[];
|
|
60
|
+
};
|
|
61
|
+
requireUserVerification?: boolean;
|
|
62
|
+
}): Promise<VerifiedAuthenticationResponse>;
|
|
63
|
+
//# sourceMappingURL=verify-authentication-response.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-authentication-response.d.cts","sourceRoot":"","sources":["../../src/webauthn/verify-authentication-response.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,4BAA4B,EAAE,qBAAiB;AAM7D,OAAO,KAAK,EAAE,6BAA6B,EAAE,oBAAgB;AAG7D,MAAM,MAAM,8BAA8B,GACtC;IAAE,QAAQ,EAAE,KAAK,CAAC;IAAC,kBAAkB,CAAC,EAAE,KAAK,CAAA;CAAE,GAC/C;IACE,QAAQ,EAAE,IAAI,CAAC;IACf,kBAAkB,EAAE;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,OAAO,CAAC;QACtB,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH,CAAC;AAEN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAsB,4BAA4B,CAAC,IAAI,EAAE;IACvD,QAAQ,EAAE,6BAA6B,CAAC;IACxC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE;QACV,EAAE,EAAE,MAAM,CAAC;QACX,SAAS,EAAE,UAAU,CAAC;QACtB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,4BAA4B,EAAE,CAAC;KAC7C,CAAC;IACF,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC,GAAG,OAAO,CAAC,8BAA8B,CAAC,CA+I1C"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { AuthenticatorTransportFuture } from "../types.mjs";
|
|
2
|
+
import type { PasskeyAuthenticationResponse } from "./types.mjs";
|
|
3
|
+
export type VerifiedAuthenticationResponse = {
|
|
4
|
+
verified: false;
|
|
5
|
+
authenticationInfo?: never;
|
|
6
|
+
} | {
|
|
7
|
+
verified: true;
|
|
8
|
+
authenticationInfo: {
|
|
9
|
+
credentialId: string;
|
|
10
|
+
newCounter: number;
|
|
11
|
+
userVerified: boolean;
|
|
12
|
+
origin: string;
|
|
13
|
+
rpID: string;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Verifies a WebAuthn authentication (assertion) response per
|
|
18
|
+
* W3C WebAuthn Level 3 §7.2.
|
|
19
|
+
*
|
|
20
|
+
* Performs the following checks in order:
|
|
21
|
+
* 1. Credential ID presence, base64url consistency, and type.
|
|
22
|
+
* 2. `clientDataJSON` -- type is `"webauthn.get"`, challenge and origin
|
|
23
|
+
* match.
|
|
24
|
+
* 3. `authenticatorData` -- RP ID hash matches, user-presence flag is
|
|
25
|
+
* set, and optional user-verification flag is checked.
|
|
26
|
+
* 4. Signature verification -- `signature` is verified over
|
|
27
|
+
* `authData || SHA-256(clientDataJSON)` using the stored credential
|
|
28
|
+
* public key (COSE-encoded).
|
|
29
|
+
* 5. Counter monotonicity -- if either the stored or returned counter
|
|
30
|
+
* is non-zero, the new counter must exceed the stored value.
|
|
31
|
+
*
|
|
32
|
+
* @param opts - Verification options.
|
|
33
|
+
* @param opts.response - The `PublicKeyCredential` result from
|
|
34
|
+
* `navigator.credentials.get()`, serialized as JSON.
|
|
35
|
+
* @param opts.expectedChallenge - The base64url challenge that was issued
|
|
36
|
+
* for this ceremony.
|
|
37
|
+
* @param opts.expectedOrigin - One or more acceptable origins.
|
|
38
|
+
* @param opts.expectedRPID - The Relying Party ID domain.
|
|
39
|
+
* @param opts.credential - The stored credential record to verify against.
|
|
40
|
+
* @param opts.credential.id - The credential ID (base64url).
|
|
41
|
+
* @param opts.credential.publicKey - The COSE-encoded public key bytes
|
|
42
|
+
* persisted during registration.
|
|
43
|
+
* @param opts.credential.counter - The last known signature counter value.
|
|
44
|
+
* @param opts.credential.transports - Optional authenticator transports.
|
|
45
|
+
* @param opts.requireUserVerification - When `true`, verification fails
|
|
46
|
+
* if the UV flag is not set. Defaults to `false`.
|
|
47
|
+
* @returns Verification result containing `verified` status and parsed
|
|
48
|
+
* authentication info (new counter, origin, RP ID).
|
|
49
|
+
*/
|
|
50
|
+
export declare function verifyAuthenticationResponse(opts: {
|
|
51
|
+
response: PasskeyAuthenticationResponse;
|
|
52
|
+
expectedChallenge: string;
|
|
53
|
+
expectedOrigin: string | string[];
|
|
54
|
+
expectedRPID: string;
|
|
55
|
+
credential: {
|
|
56
|
+
id: string;
|
|
57
|
+
publicKey: Uint8Array;
|
|
58
|
+
counter: number;
|
|
59
|
+
transports?: AuthenticatorTransportFuture[];
|
|
60
|
+
};
|
|
61
|
+
requireUserVerification?: boolean;
|
|
62
|
+
}): Promise<VerifiedAuthenticationResponse>;
|
|
63
|
+
//# sourceMappingURL=verify-authentication-response.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-authentication-response.d.mts","sourceRoot":"","sources":["../../src/webauthn/verify-authentication-response.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,4BAA4B,EAAE,qBAAiB;AAM7D,OAAO,KAAK,EAAE,6BAA6B,EAAE,oBAAgB;AAG7D,MAAM,MAAM,8BAA8B,GACtC;IAAE,QAAQ,EAAE,KAAK,CAAC;IAAC,kBAAkB,CAAC,EAAE,KAAK,CAAA;CAAE,GAC/C;IACE,QAAQ,EAAE,IAAI,CAAC;IACf,kBAAkB,EAAE;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,OAAO,CAAC;QACtB,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH,CAAC;AAEN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAsB,4BAA4B,CAAC,IAAI,EAAE;IACvD,QAAQ,EAAE,6BAA6B,CAAC;IACxC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE;QACV,EAAE,EAAE,MAAM,CAAC;QACX,SAAS,EAAE,UAAU,CAAC;QACtB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,4BAA4B,EAAE,CAAC;KAC7C,CAAC;IACF,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC,GAAG,OAAO,CAAC,8BAA8B,CAAC,CA+I1C"}
|