UNPKG

@clerk/shared

Version:

Internal package utils used by the Clerk SDKs

1 lines 11.4 kB
{"version":3,"file":"passkeys.mjs","names":[],"sources":["../../../src/internal/clerk-js/passkeys.ts"],"sourcesContent":["import type { ClerkRuntimeError } from '../../error';\nimport { ClerkWebAuthnError } from '../../error';\nimport type {\n CredentialReturn,\n PublicKeyCredentialCreationOptionsJSON,\n PublicKeyCredentialCreationOptionsWithoutExtensions,\n PublicKeyCredentialRequestOptionsJSON,\n PublicKeyCredentialRequestOptionsWithoutExtensions,\n PublicKeyCredentialWithAuthenticatorAssertionResponse,\n PublicKeyCredentialWithAuthenticatorAttestationResponse,\n} from '../../types';\n\ntype WebAuthnCreateCredentialReturn = CredentialReturn<PublicKeyCredentialWithAuthenticatorAttestationResponse>;\ntype WebAuthnGetCredentialReturn = CredentialReturn<PublicKeyCredentialWithAuthenticatorAssertionResponse>;\n\nclass Base64Converter {\n static encode(buffer: ArrayBuffer): string {\n return btoa(String.fromCharCode(...new Uint8Array(buffer)))\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n }\n\n static decode(base64url: string): ArrayBuffer {\n const base64 = base64url.replace(/-/g, '+').replace(/_/g, '/');\n\n const binaryString = atob(base64);\n const length = binaryString.length;\n const bytes = new Uint8Array(length);\n for (let i = 0; i < length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes.buffer;\n }\n}\n\nasync function webAuthnCreateCredential(\n publicKeyOptions: PublicKeyCredentialCreationOptionsWithoutExtensions,\n): Promise<WebAuthnCreateCredentialReturn> {\n try {\n // Typescript types are not aligned with the spec. These type assertions are required to comply with the spec.\n const credential = (await navigator.credentials.create({\n publicKey: publicKeyOptions,\n })) as PublicKeyCredentialWithAuthenticatorAttestationResponse | null;\n\n if (!credential) {\n return {\n error: new ClerkWebAuthnError('Browser failed to create credential', {\n code: 'passkey_registration_failed',\n }),\n publicKeyCredential: null,\n };\n }\n\n return { publicKeyCredential: credential, error: null };\n } catch (e) {\n return { error: handlePublicKeyCreateError(e as Error), publicKeyCredential: null };\n }\n}\n\nclass WebAuthnAbortService {\n private controller: AbortController | undefined;\n\n private __abort() {\n if (!this.controller) {\n return;\n }\n const abortError = new Error();\n abortError.name = 'AbortError';\n this.controller.abort(abortError);\n }\n\n createAbortSignal() {\n this.__abort();\n const newController = new AbortController();\n this.controller = newController;\n return newController.signal;\n }\n\n abort() {\n this.__abort();\n this.controller = undefined;\n }\n}\n\nconst __internal_WebAuthnAbortService = new WebAuthnAbortService();\n\nasync function webAuthnGetCredential({\n publicKeyOptions,\n conditionalUI,\n}: {\n publicKeyOptions: PublicKeyCredentialRequestOptionsWithoutExtensions;\n conditionalUI: boolean;\n}): Promise<WebAuthnGetCredentialReturn> {\n try {\n // Typescript types are not aligned with the spec. These type assertions are required to comply with the spec.\n const credential = (await navigator.credentials.get({\n publicKey: publicKeyOptions,\n mediation: conditionalUI ? 'conditional' : 'optional',\n signal: __internal_WebAuthnAbortService.createAbortSignal(),\n })) as PublicKeyCredentialWithAuthenticatorAssertionResponse | null;\n\n if (!credential) {\n return {\n error: new ClerkWebAuthnError('Browser failed to get credential', { code: 'passkey_retrieval_failed' }),\n publicKeyCredential: null,\n };\n }\n\n return { publicKeyCredential: credential, error: null };\n } catch (e) {\n return { error: handlePublicKeyGetError(e as Error), publicKeyCredential: null };\n }\n}\n\nfunction handlePublicKeyError(error: Error): ClerkWebAuthnError | ClerkRuntimeError | Error {\n if (error.name === 'AbortError') {\n return new ClerkWebAuthnError(error.message, { code: 'passkey_operation_aborted' });\n }\n if (error.name === 'SecurityError') {\n return new ClerkWebAuthnError(error.message, {\n code: 'passkey_invalid_rpID_or_domain',\n docsUrl: 'https://clerk.com/docs/deployments/overview#authentication-across-subdomains',\n });\n }\n return error;\n}\n\n/**\n * Map webauthn errors from `navigator.credentials.create()` to Clerk-js errors\n *\n * @param error\n */\nfunction handlePublicKeyCreateError(error: Error): ClerkWebAuthnError | ClerkRuntimeError | Error {\n if (error.name === 'InvalidStateError') {\n // Note: Firefox will throw 'NotAllowedError' when passkeys exists\n return new ClerkWebAuthnError(error.message, { code: 'passkey_already_exists' });\n }\n if (error.name === 'NotAllowedError') {\n return new ClerkWebAuthnError(error.message, { code: 'passkey_registration_cancelled' });\n }\n return handlePublicKeyError(error);\n}\n\n/**\n * Map webauthn errors from `navigator.credentials.get()` to Clerk-js errors\n *\n * @param error\n */\nfunction handlePublicKeyGetError(error: Error): ClerkWebAuthnError | ClerkRuntimeError | Error {\n if (error.name === 'NotAllowedError') {\n return new ClerkWebAuthnError(error.message, { code: 'passkey_retrieval_cancelled' });\n }\n return handlePublicKeyError(error);\n}\n\nfunction convertJSONToPublicKeyCreateOptions(jsonPublicKey: PublicKeyCredentialCreationOptionsJSON) {\n const userIdBuffer = base64UrlToBuffer(jsonPublicKey.user.id);\n const challengeBuffer = base64UrlToBuffer(jsonPublicKey.challenge);\n\n const excludeCredentialsWithBuffer = (jsonPublicKey.excludeCredentials || []).map(cred => ({\n ...cred,\n id: base64UrlToBuffer(cred.id),\n }));\n\n return {\n ...jsonPublicKey,\n excludeCredentials: excludeCredentialsWithBuffer,\n challenge: challengeBuffer,\n user: {\n ...jsonPublicKey.user,\n id: userIdBuffer,\n },\n } as PublicKeyCredentialCreationOptionsWithoutExtensions;\n}\n\nfunction convertJSONToPublicKeyRequestOptions(jsonPublicKey: PublicKeyCredentialRequestOptionsJSON) {\n const challengeBuffer = base64UrlToBuffer(jsonPublicKey.challenge);\n\n const allowCredentialsWithBuffer = (jsonPublicKey.allowCredentials || []).map(cred => ({\n ...cred,\n id: base64UrlToBuffer(cred.id),\n }));\n\n return {\n ...jsonPublicKey,\n allowCredentials: allowCredentialsWithBuffer,\n challenge: challengeBuffer,\n } as PublicKeyCredentialRequestOptionsWithoutExtensions;\n}\n\nfunction __serializePublicKeyCredential<T extends Omit<PublicKeyCredential, 'getClientExtensionResults'>>(pkc: T) {\n return {\n type: pkc.type,\n id: pkc.id,\n rawId: bufferToBase64Url(pkc.rawId),\n authenticatorAttachment: pkc.authenticatorAttachment,\n };\n}\n\nfunction serializePublicKeyCredential(pkc: PublicKeyCredentialWithAuthenticatorAttestationResponse) {\n const response = pkc.response;\n return {\n ...__serializePublicKeyCredential(pkc),\n response: {\n clientDataJSON: bufferToBase64Url(response.clientDataJSON),\n attestationObject: bufferToBase64Url(response.attestationObject),\n transports: response.getTransports(),\n },\n };\n}\n\nfunction serializePublicKeyCredentialAssertion(pkc: PublicKeyCredentialWithAuthenticatorAssertionResponse) {\n const response = pkc.response;\n return {\n ...__serializePublicKeyCredential(pkc),\n response: {\n clientDataJSON: bufferToBase64Url(response.clientDataJSON),\n authenticatorData: bufferToBase64Url(response.authenticatorData),\n signature: bufferToBase64Url(response.signature),\n userHandle: response.userHandle ? bufferToBase64Url(response.userHandle) : null,\n },\n };\n}\n\nconst bufferToBase64Url = Base64Converter.encode.bind(Base64Converter);\nconst base64UrlToBuffer = Base64Converter.decode.bind(Base64Converter);\n\nexport {\n base64UrlToBuffer,\n bufferToBase64Url,\n handlePublicKeyCreateError,\n webAuthnCreateCredential,\n webAuthnGetCredential,\n convertJSONToPublicKeyCreateOptions,\n convertJSONToPublicKeyRequestOptions,\n serializePublicKeyCredential,\n serializePublicKeyCredentialAssertion,\n __internal_WebAuthnAbortService,\n};\n"],"mappings":"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"}