@metamask/profile-sync-controller 34.0.3 → 35.0.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/dist/controllers/authentication/AuthenticationController-method-action-types.d.ts +25 -3
  3. package/dist/controllers/authentication/AuthenticationController-method-action-types.d.ts.map +1 -1
  4. package/dist/controllers/authentication/AuthenticationController-method-action-types.js.map +1 -1
  5. package/dist/controllers/authentication/AuthenticationController.d.ts +21 -2
  6. package/dist/controllers/authentication/AuthenticationController.d.ts.map +1 -1
  7. package/dist/controllers/authentication/AuthenticationController.js +50 -3
  8. package/dist/controllers/authentication/AuthenticationController.js.map +1 -1
  9. package/dist/controllers/authentication/index.d.ts +1 -1
  10. package/dist/controllers/authentication/index.d.ts.map +1 -1
  11. package/dist/controllers/authentication/index.js.map +1 -1
  12. package/dist/sdk/authentication-jwt-bearer/flow-srp.d.ts +15 -4
  13. package/dist/sdk/authentication-jwt-bearer/flow-srp.d.ts.map +1 -1
  14. package/dist/sdk/authentication-jwt-bearer/flow-srp.js +34 -6
  15. package/dist/sdk/authentication-jwt-bearer/flow-srp.js.map +1 -1
  16. package/dist/sdk/authentication-jwt-bearer/mfa/schemas.d.ts +23 -10
  17. package/dist/sdk/authentication-jwt-bearer/mfa/schemas.d.ts.map +1 -1
  18. package/dist/sdk/authentication-jwt-bearer/mfa/schemas.js +20 -8
  19. package/dist/sdk/authentication-jwt-bearer/mfa/schemas.js.map +1 -1
  20. package/dist/sdk/authentication-jwt-bearer/mfa/services.d.ts +19 -0
  21. package/dist/sdk/authentication-jwt-bearer/mfa/services.d.ts.map +1 -1
  22. package/dist/sdk/authentication-jwt-bearer/mfa/services.js +65 -10
  23. package/dist/sdk/authentication-jwt-bearer/mfa/services.js.map +1 -1
  24. package/dist/sdk/authentication-jwt-bearer/mfa/types.d.ts +44 -22
  25. package/dist/sdk/authentication-jwt-bearer/mfa/types.d.ts.map +1 -1
  26. package/dist/sdk/authentication-jwt-bearer/mfa/types.js.map +1 -1
  27. package/dist/sdk/authentication-jwt-bearer/services.d.ts +12 -1
  28. package/dist/sdk/authentication-jwt-bearer/services.d.ts.map +1 -1
  29. package/dist/sdk/authentication-jwt-bearer/services.js +56 -14
  30. package/dist/sdk/authentication-jwt-bearer/services.js.map +1 -1
  31. package/dist/sdk/authentication-jwt-bearer/types.d.ts +9 -0
  32. package/dist/sdk/authentication-jwt-bearer/types.d.ts.map +1 -1
  33. package/dist/sdk/authentication-jwt-bearer/types.js.map +1 -1
  34. package/dist/sdk/authentication.d.ts +3 -2
  35. package/dist/sdk/authentication.d.ts.map +1 -1
  36. package/dist/sdk/authentication.js +6 -2
  37. package/dist/sdk/authentication.js.map +1 -1
  38. package/dist/sdk/constants.d.ts +1 -0
  39. package/dist/sdk/constants.d.ts.map +1 -1
  40. package/dist/sdk/constants.js +1 -0
  41. package/dist/sdk/constants.js.map +1 -1
  42. package/dist/sdk/errors.d.ts +10 -1
  43. package/dist/sdk/errors.d.ts.map +1 -1
  44. package/dist/sdk/errors.js +12 -0
  45. package/dist/sdk/errors.js.map +1 -1
  46. package/dist/sdk/mocks/auth.d.ts +18 -0
  47. package/dist/sdk/mocks/auth.d.ts.map +1 -1
  48. package/dist/sdk/mocks/auth.js +19 -1
  49. package/dist/sdk/mocks/auth.js.map +1 -1
  50. package/package.json +9 -9
@@ -11,23 +11,63 @@ export const MFA_VERIFY_URL = (env) => `${getEnvUrls(env).authApiUrl}/api/v2/mfa
11
11
  export const MFA_VERIFY_COMPLETE_URL = (env) => `${getEnvUrls(env).authApiUrl}/api/v2/mfa/verify/complete`;
12
12
  export const MFA_CREDENTIALS_URL = (env) => `${getEnvUrls(env).authApiUrl}/api/v2/mfa/credentials`;
13
13
  /**
14
- * Reads a credential's enrollment date. Unlike flow deadlines, this is display
15
- * metadata, so an unparsable value is dropped instead of rejecting the whole
16
- * credential list.
14
+ * Name an authenticator app shows for the account added from `setupUri`.
17
15
  *
18
- * @param value - The raw `enrolled_at` value, if the server sent one.
16
+ * The server's QR code names the account after its own Kratos config (issuer
17
+ * "MetaMask Identity", account "MetaMask <8 hex>" from the identity's
18
+ * username), which is not sent in the enrollment response. A different name
19
+ * is harmless: users add the account once, through either the QR code or this
20
+ * link, and the codes only depend on the secret and `TOTP_SETTINGS`.
21
+ */
22
+ const TOTP_SETUP_LABEL = 'MetaMask';
23
+ /**
24
+ * Settings Kratos uses for every TOTP key: its `NewKey` hard-codes 6 digits
25
+ * and a 30-second period, and leaves the algorithm at the library default,
26
+ * SHA1. They are not part of the server's configuration, and changing them
27
+ * would break every authenticator app already set up, so they are stable
28
+ * enough to copy here.
29
+ */
30
+ const TOTP_SETTINGS = { algorithm: 'SHA1', digits: '6', period: '30' };
31
+ /**
32
+ * Builds the `otpauth://` link that opens an authenticator app with the
33
+ * account to add, for devices that cannot scan their own screen.
34
+ *
35
+ * It is built here rather than sent by the server because Kratos does not
36
+ * expose it: its settings flow returns only the secret and the QR code image,
37
+ * and keeps the link in internal flow data that its API never returns. The
38
+ * server could only rebuild it the same way, from the same fixed settings, or
39
+ * by decoding its own QR code.
40
+ *
41
+ * @param secret - Base32 secret from the enrollment response.
42
+ * @returns The setup link. It contains the secret: never log or persist it.
43
+ */
44
+ export function buildTotpSetupUri(secret) {
45
+ const params = new URLSearchParams({
46
+ secret,
47
+ issuer: TOTP_SETUP_LABEL,
48
+ ...TOTP_SETTINGS,
49
+ });
50
+ return `otpauth://totp/${encodeURIComponent(TOTP_SETUP_LABEL)}?${params.toString()}`;
51
+ }
52
+ /**
53
+ * Reads a credential date (`enrolled_at`, `last_used_at`). Unlike flow
54
+ * deadlines, these are display metadata, so an unparsable value is dropped
55
+ * instead of rejecting the whole credential list.
56
+ *
57
+ * @param field - The field name, for the log.
58
+ * @param value - The raw value, if the server sent one.
19
59
  * @returns The epoch milliseconds, or undefined when absent or unparsable.
20
60
  */
21
- function parseEnrolledAt(value) {
61
+ function parseCredentialDate(field, value) {
22
62
  if (!value) {
23
63
  return undefined;
24
64
  }
25
- const enrolledAt = Date.parse(value);
26
- if (Number.isNaN(enrolledAt)) {
27
- log.warn(`Ignoring unparsable MFA credential enrolled_at: ${value}`);
65
+ const date = Date.parse(value);
66
+ if (Number.isNaN(date)) {
67
+ log.warn(`Ignoring unparsable MFA credential ${field}: ${value}`);
28
68
  return undefined;
29
69
  }
30
- return enrolledAt;
70
+ return date;
31
71
  }
32
72
  function parseExpiresAt(value) {
33
73
  const expiresAt = Date.parse(value);
@@ -139,6 +179,7 @@ async function throwMfaError(response, errorPrefix) {
139
179
  switch (code) {
140
180
  case 'credential_already_enrolled':
141
181
  case 'email_already_enrolled':
182
+ case 'totp_already_enrolled':
142
183
  case 'email_socially_verified':
143
184
  throw new CredentialAlreadyEnrolledError(code, message, status);
144
185
  case 'credential_not_enrolled':
@@ -229,6 +270,15 @@ export async function mfaEnroll(env, accessToken, body) {
229
270
  ...(json.passkey_create_data
230
271
  ? { publicKey: parsePasskeyCreateData(json.passkey_create_data) }
231
272
  : {}),
273
+ ...(json.totp_secret && json.totp_qr
274
+ ? {
275
+ totp: {
276
+ secret: json.totp_secret,
277
+ qrCode: json.totp_qr,
278
+ setupUri: buildTotpSetupUri(json.totp_secret),
279
+ },
280
+ }
281
+ : {}),
232
282
  };
233
283
  }
234
284
  /**
@@ -328,10 +378,12 @@ export function toEnrolledCredential(credential) {
328
378
  log.warn(`Ignoring MFA credential with unsupported status: ${status}`);
329
379
  return null;
330
380
  }
331
- const enrolledAt = parseEnrolledAt(credential.enrolled_at);
381
+ const enrolledAt = parseCredentialDate('enrolled_at', credential.enrolled_at);
382
+ const lastUsedAt = parseCredentialDate('last_used_at', credential.last_used_at);
332
383
  const base = {
333
384
  status,
334
385
  ...(enrolledAt === undefined ? {} : { enrolledAt }),
386
+ ...(lastUsedAt === undefined ? {} : { lastUsedAt }),
335
387
  };
336
388
  if (type === 'passkey') {
337
389
  return {
@@ -353,6 +405,9 @@ export function toEnrolledCredential(credential) {
353
405
  verified: credential.email?.verified ?? status === 'active',
354
406
  };
355
407
  }
408
+ if (type === 'totp') {
409
+ return { type, ...base };
410
+ }
356
411
  log.warn(`Ignoring unsupported or incomplete MFA credential: ${type}`);
357
412
  return null;
358
413
  }
@@ -1 +1 @@
1
- {"version":3,"file":"services.js","sourceRoot":"","sources":["../../../../src/sdk/authentication-jwt-bearer/mfa/services.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Json } from '@metamask/utils';\nimport log from 'loglevel';\n\nimport type { Env } from '../../../shared/env.js';\nimport { getEnvUrls } from '../../../shared/env.js';\nimport { HTTP_STATUS_CODES } from '../../constants.js';\nimport {\n CredentialAlreadyEnrolledError,\n CredentialNotEnrolledError,\n MaxIdentifiersReachedError,\n MaxPasskeysReachedError,\n MfaError,\n MfaFlowExpiredError,\n MfaIdentityMissingError,\n MfaRateLimitedError,\n MfaUnavailableError,\n MfaVerificationFailedError,\n OtpResendCooldownError,\n StepUpRequiredError,\n TooManyAttemptsError,\n} from '../../errors.js';\nimport { asRecord } from '../../utils/as-record.js';\nimport { toErrorMessage } from '../../utils/to-error-message.js';\nimport {\n AuthenticationResponseJSONStruct,\n MfaCredentialsResponseStruct,\n MfaEnrollCompleteResponseStruct,\n MfaEnrollResponseStruct,\n MfaErrorResponseStruct,\n MfaVerifyCompleteResponseStruct,\n MfaVerifyResponseStruct,\n PasskeyCreateDataStruct,\n PasskeyRequestDataStruct,\n RegistrationResponseJSONStruct,\n assertValidMfaRequest,\n assertValidMfaResponse,\n} from './schemas.js';\nimport type {\n AuthenticationResponseJSON,\n EnrolledCredential,\n MfaCredential,\n MfaCredentialStatus,\n MfaCredentialType,\n MfaEnrollCompleteRequest,\n MfaEnrollRequest,\n MfaVerifyCompleteRequest,\n MfaVerifyRequest,\n PublicKeyCredentialCreationOptionsJSON as PasskeyCreationOptions,\n PublicKeyCredentialRequestOptionsJSON as PasskeyRequestOptions,\n RegistrationResponseJSON,\n} from './types.js';\n\nexport const MFA_ENROLL_URL = (env: Env): string =>\n `${getEnvUrls(env).authApiUrl}/api/v2/mfa/enroll`;\n\nexport const MFA_ENROLL_COMPLETE_URL = (env: Env): string =>\n `${getEnvUrls(env).authApiUrl}/api/v2/mfa/enroll/complete`;\n\nexport const MFA_VERIFY_URL = (env: Env): string =>\n `${getEnvUrls(env).authApiUrl}/api/v2/mfa/verify`;\n\nexport const MFA_VERIFY_COMPLETE_URL = (env: Env): string =>\n `${getEnvUrls(env).authApiUrl}/api/v2/mfa/verify/complete`;\n\nexport const MFA_CREDENTIALS_URL = (env: Env): string =>\n `${getEnvUrls(env).authApiUrl}/api/v2/mfa/credentials`;\n\ntype EnrollmentServiceResult = {\n flowId: string;\n expiresAt: number;\n publicKey?: PasskeyCreationOptions;\n};\n\ntype VerificationServiceResult = {\n flowId: string;\n expiresAt: number;\n publicKey?: PasskeyRequestOptions;\n};\n\nexport type MfaVerificationAssertion = {\n /** Assertion JWT to exchange at Hydra for an access token. */\n token: string;\n /** Assertion lifetime in seconds. */\n expiresIn: number;\n};\n\ntype EnrollmentCompletionParams = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n credential_type: MfaCredentialType;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n flow_id: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n otp_code?: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n passkey_attestation?: RegistrationResponseJSON;\n};\n\ntype VerificationCompletionParams = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n credential_type: MfaCredentialType;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n flow_id: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n otp_code?: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n passkey_assertion?: AuthenticationResponseJSON;\n};\n\n/**\n * Reads a credential's enrollment date. Unlike flow deadlines, this is display\n * metadata, so an unparsable value is dropped instead of rejecting the whole\n * credential list.\n *\n * @param value - The raw `enrolled_at` value, if the server sent one.\n * @returns The epoch milliseconds, or undefined when absent or unparsable.\n */\nfunction parseEnrolledAt(value: string | undefined): number | undefined {\n if (!value) {\n return undefined;\n }\n const enrolledAt = Date.parse(value);\n if (Number.isNaN(enrolledAt)) {\n log.warn(`Ignoring unparsable MFA credential enrolled_at: ${value}`);\n return undefined;\n }\n return enrolledAt;\n}\n\nfunction parseExpiresAt(value: string): number {\n const expiresAt = Date.parse(value);\n if (Number.isNaN(expiresAt)) {\n throw new MfaError('invalid_response', `Invalid expires_at: ${value}`);\n }\n return expiresAt;\n}\n\n/**\n * Parses passkey creation data embedded in an enrollment response.\n *\n * @param value - JSON-encoded creation options.\n * @returns Validated public-key creation options.\n */\nexport function parsePasskeyCreateData(value: string): PasskeyCreationOptions {\n try {\n const parsed: unknown = JSON.parse(value);\n assertValidMfaResponse(parsed, PasskeyCreateDataStruct);\n return parsed.publicKey;\n } catch (error) {\n if (error instanceof MfaError) {\n throw error;\n }\n const message = toErrorMessage(error);\n throw new MfaError('invalid_response', message);\n }\n}\n\n/**\n * Parses passkey request data embedded in a verification response.\n *\n * @param value - JSON-encoded request options.\n * @returns Validated public-key request options.\n */\nexport function parsePasskeyRequestData(value: string): PasskeyRequestOptions {\n try {\n const parsed: unknown = JSON.parse(value);\n assertValidMfaResponse(parsed, PasskeyRequestDataStruct);\n return parsed.publicKey;\n } catch (error) {\n if (error instanceof MfaError) {\n throw error;\n }\n const message = toErrorMessage(error);\n throw new MfaError('invalid_response', message);\n }\n}\n\n/**\n * Reads a `Retry-After` header as a delay. The human-readable error message is\n * deliberately not parsed: the API documents it as unstable.\n *\n * @param response - The throttled response.\n * @returns The delay in milliseconds, or undefined without a usable header.\n */\nfunction parseRetryAfter(response: Response): number | undefined {\n const header = response.headers.get('Retry-After');\n if (!header) {\n return undefined;\n }\n const seconds = Number(header);\n if (Number.isInteger(seconds)) {\n return Math.max(0, seconds * 1000);\n }\n const date = Date.parse(header);\n return Number.isNaN(date) ? undefined : Math.max(0, date - Date.now());\n}\n\n/**\n * Reads and validates the JSON error body of a failed MFA request.\n *\n * When the body parses as JSON but does not match the documented error\n * shape, a `message` field is salvaged if present so callers still get a\n * useful diagnostic instead of a content-free fallback.\n *\n * @param response - The failed response.\n * @returns The validated error body, a best-effort salvage of it, or\n * undefined when the body could not be parsed as JSON at all.\n */\ntype MfaErrorBody = {\n code?: string;\n message: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n retry_after_seconds?: number;\n};\n\n/**\n * Prefers the documented `retry_after_seconds` error field over the\n * `Retry-After` header.\n *\n * @param body - The parsed error body, if any.\n * @param response - The throttled response.\n * @returns The delay in milliseconds, or undefined when neither is usable.\n */\nfunction resolveRetryAfterMs(\n body: MfaErrorBody | undefined,\n response: Response,\n): number | undefined {\n return body?.retry_after_seconds === undefined\n ? parseRetryAfter(response)\n : body.retry_after_seconds * 1000;\n}\n\nasync function readErrorBody(\n response: Response,\n): Promise<MfaErrorBody | undefined> {\n let body: unknown;\n try {\n body = await response.json();\n } catch {\n return undefined;\n }\n\n try {\n assertValidMfaResponse(body, MfaErrorResponseStruct);\n return body;\n } catch {\n const message = asRecord(body)?.message;\n return typeof message === 'string' ? { message } : undefined;\n }\n}\n\nasync function throwMfaError(\n response: Response,\n errorPrefix: string,\n): Promise<never> {\n const { status } = response;\n const body = await readErrorBody(response);\n const message = `${errorPrefix}: ${body?.message ?? `HTTP ${status}`}`;\n\n // Status-only classification first: gateways and load balancers answer\n // 401/429/502 without the service's JSON body, and the caller still needs\n // to invalidate its session, honour Retry-After, or back off.\n if (status === HTTP_STATUS_CODES.UNAUTHORIZED) {\n throw new MfaError('authentication_required', message, { status });\n }\n\n const code = body?.code;\n switch (code) {\n case 'credential_already_enrolled':\n case 'email_already_enrolled':\n case 'email_socially_verified':\n throw new CredentialAlreadyEnrolledError(code, message, status);\n case 'credential_not_enrolled':\n throw new CredentialNotEnrolledError(message, status);\n case 'aal2_required':\n throw new StepUpRequiredError(message, status);\n case 'flow_expired':\n case 'invalid_flow':\n throw new MfaFlowExpiredError(code, message, status);\n case 'mfa_identity_missing':\n throw new MfaIdentityMissingError(message, status);\n case 'invalid_code':\n case 'invalid_attestation':\n case 'invalid_assertion':\n throw new MfaVerificationFailedError(code, message, status);\n case 'too_many_attempts':\n throw new TooManyAttemptsError(message, status);\n case 'max_passkeys_reached':\n throw new MaxPasskeysReachedError(message, status);\n case 'max_identifiers_reached':\n throw new MaxIdentifiersReachedError(message, status);\n case 'otp_resend_cooldown':\n throw new OtpResendCooldownError(\n message,\n resolveRetryAfterMs(body, response),\n status,\n );\n case 'kratos_unavailable':\n throw new MfaUnavailableError(message, status);\n default:\n break;\n }\n\n if (status === HTTP_STATUS_CODES.TOO_MANY_REQUESTS) {\n throw new MfaRateLimitedError(\n message,\n resolveRetryAfterMs(body, response),\n status,\n );\n }\n if (status === HTTP_STATUS_CODES.BAD_GATEWAY) {\n throw new MfaUnavailableError(message, status);\n }\n if (!body) {\n throw new MfaError(\n 'invalid_response',\n `${errorPrefix}: Unexpected error response (HTTP ${status})`,\n { status },\n );\n }\n throw new MfaError(code ?? 'server_error', message, { status });\n}\n\nasync function requestJson(\n url: string,\n accessToken: string,\n init?: { method?: 'GET' | 'POST'; body?: Json },\n): Promise<Json> {\n let response: Response;\n try {\n response = await fetch(url, {\n method: init?.method ?? 'GET',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n ...(init?.body === undefined\n ? {}\n : { 'Content-Type': 'application/json' }),\n },\n ...(init?.body === undefined ? {} : { body: JSON.stringify(init.body) }),\n });\n } catch (error) {\n const message = toErrorMessage(error);\n throw new MfaUnavailableError(`MFA request failed: ${message}`);\n }\n\n if (!response.ok) {\n return await throwMfaError(response, 'MFA request failed');\n }\n\n try {\n return await response.json();\n } catch (error) {\n const message = toErrorMessage(error);\n throw new MfaError('invalid_response', message, {\n status: response.status,\n });\n }\n}\n\n/**\n * Begins enrollment of an MFA credential.\n *\n * @param env - Authentication environment.\n * @param accessToken - Primary profile access token.\n * @param body - Enrollment request.\n * @returns Validated enrollment flow data.\n */\nexport async function mfaEnroll(\n env: Env,\n accessToken: string,\n body: MfaEnrollRequest,\n): Promise<EnrollmentServiceResult> {\n const json = await requestJson(MFA_ENROLL_URL(env), accessToken, {\n method: 'POST',\n body,\n });\n assertValidMfaResponse(json, MfaEnrollResponseStruct);\n\n return {\n flowId: json.flow_id,\n expiresAt: parseExpiresAt(json.expires_at),\n ...(json.passkey_create_data\n ? { publicKey: parsePasskeyCreateData(json.passkey_create_data) }\n : {}),\n };\n}\n\n/**\n * Completes enrollment of an MFA credential.\n *\n * @param env - Authentication environment.\n * @param accessToken - Primary profile access token.\n * @param params - Flow identifier and enrollment proof.\n * @returns The assertion JWT proving the enrolled credential, and its lifetime\n * in seconds.\n */\nexport async function mfaEnrollComplete(\n env: Env,\n accessToken: string,\n params: EnrollmentCompletionParams,\n): Promise<MfaVerificationAssertion> {\n let body: MfaEnrollCompleteRequest = {\n credential_type: params.credential_type,\n flow_id: params.flow_id,\n ...(params.otp_code ? { otp_code: params.otp_code } : {}),\n };\n if (params.passkey_attestation) {\n assertValidMfaRequest(\n params.passkey_attestation,\n RegistrationResponseJSONStruct,\n );\n body = {\n ...body,\n passkey_attestation: JSON.stringify(params.passkey_attestation),\n };\n }\n\n const json = await requestJson(MFA_ENROLL_COMPLETE_URL(env), accessToken, {\n method: 'POST',\n body,\n });\n assertValidMfaResponse(json, MfaEnrollCompleteResponseStruct);\n return { token: json.token, expiresIn: json.expires_in };\n}\n\n/**\n * Begins verification with an enrolled credential.\n *\n * @param env - Authentication environment.\n * @param accessToken - Primary profile access token.\n * @param body - Verification request.\n * @returns Validated verification flow data.\n */\nexport async function mfaVerify(\n env: Env,\n accessToken: string,\n body: MfaVerifyRequest,\n): Promise<VerificationServiceResult> {\n const json = await requestJson(MFA_VERIFY_URL(env), accessToken, {\n method: 'POST',\n body,\n });\n assertValidMfaResponse(json, MfaVerifyResponseStruct);\n\n return {\n flowId: json.flow_id,\n expiresAt: parseExpiresAt(json.expires_at),\n ...(json.passkey_request_data\n ? { publicKey: parsePasskeyRequestData(json.passkey_request_data) }\n : {}),\n };\n}\n\n/**\n * Completes verification with an enrolled credential.\n *\n * @param env - Authentication environment.\n * @param accessToken - Primary profile access token.\n * @param params - Flow identifier and verification proof.\n * @returns The assertion JWT and its lifetime in seconds.\n */\nexport async function mfaVerifyComplete(\n env: Env,\n accessToken: string,\n params: VerificationCompletionParams,\n): Promise<MfaVerificationAssertion> {\n let body: MfaVerifyCompleteRequest = {\n credential_type: params.credential_type,\n flow_id: params.flow_id,\n ...(params.otp_code ? { otp_code: params.otp_code } : {}),\n };\n if (params.passkey_assertion) {\n assertValidMfaRequest(\n params.passkey_assertion,\n AuthenticationResponseJSONStruct,\n );\n body = {\n ...body,\n passkey_assertion: JSON.stringify(params.passkey_assertion),\n };\n }\n\n const json = await requestJson(MFA_VERIFY_COMPLETE_URL(env), accessToken, {\n method: 'POST',\n body,\n });\n assertValidMfaResponse(json, MfaVerifyCompleteResponseStruct);\n return { token: json.token, expiresIn: json.expires_in };\n}\n\nfunction isSupportedStatus(status: string): status is MfaCredentialStatus {\n return status === 'active' || status === 'pending';\n}\n\n/**\n * Maps a server credential to its public controller representation.\n *\n * Unknown credential types or statuses are dropped so the server can extend\n * either without invalidating the whole list.\n *\n * @param credential - Validated server credential.\n * @returns A supported credential, or null when it cannot be represented.\n */\nexport function toEnrolledCredential(\n credential: MfaCredential,\n): EnrolledCredential | null {\n const { credential_type: type, status } = credential;\n if (!isSupportedStatus(status)) {\n log.warn(`Ignoring MFA credential with unsupported status: ${status}`);\n return null;\n }\n\n const enrolledAt = parseEnrolledAt(credential.enrolled_at);\n const base = {\n status,\n ...(enrolledAt === undefined ? {} : { enrolledAt }),\n };\n\n if (type === 'passkey') {\n return {\n type,\n ...base,\n ...(credential.passkey?.display_name\n ? { displayName: credential.passkey.display_name }\n : {}),\n };\n }\n\n if (type === 'email_otp') {\n // The API marks the address optional, so a row without one is kept.\n const address = credential.email?.address;\n return {\n type,\n ...base,\n ...(address === undefined ? {} : { email: address }),\n // The spec marks `verified` optional; an active row is verified.\n verified: credential.email?.verified ?? status === 'active',\n };\n }\n\n log.warn(`Ignoring unsupported or incomplete MFA credential: ${type}`);\n return null;\n}\n\n/**\n * Gets the credentials enrolled on the canonical profile.\n *\n * @param env - Authentication environment.\n * @param accessToken - Primary profile access token.\n * @returns Supported enrolled credentials.\n */\nexport async function getMfaCredentials(\n env: Env,\n accessToken: string,\n): Promise<EnrolledCredential[]> {\n const json = await requestJson(MFA_CREDENTIALS_URL(env), accessToken);\n assertValidMfaResponse(json, MfaCredentialsResponseStruct);\n return json.credentials\n .map(toEnrolledCredential)\n .filter((credential): credential is EnrolledCredential =>\n Boolean(credential),\n );\n}\n"]}
1
+ {"version":3,"file":"services.js","sourceRoot":"","sources":["../../../../src/sdk/authentication-jwt-bearer/mfa/services.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Json } from '@metamask/utils';\nimport log from 'loglevel';\n\nimport type { Env } from '../../../shared/env.js';\nimport { getEnvUrls } from '../../../shared/env.js';\nimport { HTTP_STATUS_CODES } from '../../constants.js';\nimport {\n CredentialAlreadyEnrolledError,\n CredentialNotEnrolledError,\n MaxIdentifiersReachedError,\n MaxPasskeysReachedError,\n MfaError,\n MfaFlowExpiredError,\n MfaIdentityMissingError,\n MfaRateLimitedError,\n MfaUnavailableError,\n MfaVerificationFailedError,\n OtpResendCooldownError,\n StepUpRequiredError,\n TooManyAttemptsError,\n} from '../../errors.js';\nimport { asRecord } from '../../utils/as-record.js';\nimport { toErrorMessage } from '../../utils/to-error-message.js';\nimport {\n AuthenticationResponseJSONStruct,\n MfaCredentialsResponseStruct,\n MfaEnrollCompleteResponseStruct,\n MfaEnrollResponseStruct,\n MfaErrorResponseStruct,\n MfaVerifyCompleteResponseStruct,\n MfaVerifyResponseStruct,\n PasskeyCreateDataStruct,\n PasskeyRequestDataStruct,\n RegistrationResponseJSONStruct,\n assertValidMfaRequest,\n assertValidMfaResponse,\n} from './schemas.js';\nimport type {\n AuthenticationResponseJSON,\n EnrolledCredential,\n MfaCredential,\n MfaCredentialStatus,\n MfaCredentialType,\n MfaEnrollCompleteRequest,\n MfaEnrollRequest,\n MfaVerifyCompleteRequest,\n MfaVerifyRequest,\n PublicKeyCredentialCreationOptionsJSON as PasskeyCreationOptions,\n PublicKeyCredentialRequestOptionsJSON as PasskeyRequestOptions,\n RegistrationResponseJSON,\n} from './types.js';\n\nexport const MFA_ENROLL_URL = (env: Env): string =>\n `${getEnvUrls(env).authApiUrl}/api/v2/mfa/enroll`;\n\nexport const MFA_ENROLL_COMPLETE_URL = (env: Env): string =>\n `${getEnvUrls(env).authApiUrl}/api/v2/mfa/enroll/complete`;\n\nexport const MFA_VERIFY_URL = (env: Env): string =>\n `${getEnvUrls(env).authApiUrl}/api/v2/mfa/verify`;\n\nexport const MFA_VERIFY_COMPLETE_URL = (env: Env): string =>\n `${getEnvUrls(env).authApiUrl}/api/v2/mfa/verify/complete`;\n\nexport const MFA_CREDENTIALS_URL = (env: Env): string =>\n `${getEnvUrls(env).authApiUrl}/api/v2/mfa/credentials`;\n\ntype EnrollmentServiceResult = {\n flowId: string;\n expiresAt: number;\n publicKey?: PasskeyCreationOptions;\n totp?: { secret: string; qrCode: string; setupUri: string };\n};\n\n/**\n * Name an authenticator app shows for the account added from `setupUri`.\n *\n * The server's QR code names the account after its own Kratos config (issuer\n * \"MetaMask Identity\", account \"MetaMask <8 hex>\" from the identity's\n * username), which is not sent in the enrollment response. A different name\n * is harmless: users add the account once, through either the QR code or this\n * link, and the codes only depend on the secret and `TOTP_SETTINGS`.\n */\nconst TOTP_SETUP_LABEL = 'MetaMask';\n\n/**\n * Settings Kratos uses for every TOTP key: its `NewKey` hard-codes 6 digits\n * and a 30-second period, and leaves the algorithm at the library default,\n * SHA1. They are not part of the server's configuration, and changing them\n * would break every authenticator app already set up, so they are stable\n * enough to copy here.\n */\nconst TOTP_SETTINGS = { algorithm: 'SHA1', digits: '6', period: '30' };\n\n/**\n * Builds the `otpauth://` link that opens an authenticator app with the\n * account to add, for devices that cannot scan their own screen.\n *\n * It is built here rather than sent by the server because Kratos does not\n * expose it: its settings flow returns only the secret and the QR code image,\n * and keeps the link in internal flow data that its API never returns. The\n * server could only rebuild it the same way, from the same fixed settings, or\n * by decoding its own QR code.\n *\n * @param secret - Base32 secret from the enrollment response.\n * @returns The setup link. It contains the secret: never log or persist it.\n */\nexport function buildTotpSetupUri(secret: string): string {\n const params = new URLSearchParams({\n secret,\n issuer: TOTP_SETUP_LABEL,\n ...TOTP_SETTINGS,\n });\n return `otpauth://totp/${encodeURIComponent(TOTP_SETUP_LABEL)}?${params.toString()}`;\n}\n\ntype VerificationServiceResult = {\n flowId: string;\n expiresAt: number;\n publicKey?: PasskeyRequestOptions;\n};\n\nexport type MfaVerificationAssertion = {\n /** Assertion JWT to exchange at Hydra for an access token. */\n token: string;\n /** Assertion lifetime in seconds. */\n expiresIn: number;\n};\n\ntype EnrollmentCompletionParams = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n credential_type: MfaCredentialType;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n flow_id: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n otp_code?: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n passkey_attestation?: RegistrationResponseJSON;\n};\n\ntype VerificationCompletionParams = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n credential_type: MfaCredentialType;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n flow_id: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n otp_code?: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n passkey_assertion?: AuthenticationResponseJSON;\n};\n\n/**\n * Reads a credential date (`enrolled_at`, `last_used_at`). Unlike flow\n * deadlines, these are display metadata, so an unparsable value is dropped\n * instead of rejecting the whole credential list.\n *\n * @param field - The field name, for the log.\n * @param value - The raw value, if the server sent one.\n * @returns The epoch milliseconds, or undefined when absent or unparsable.\n */\nfunction parseCredentialDate(\n field: string,\n value: string | undefined,\n): number | undefined {\n if (!value) {\n return undefined;\n }\n const date = Date.parse(value);\n if (Number.isNaN(date)) {\n log.warn(`Ignoring unparsable MFA credential ${field}: ${value}`);\n return undefined;\n }\n return date;\n}\n\nfunction parseExpiresAt(value: string): number {\n const expiresAt = Date.parse(value);\n if (Number.isNaN(expiresAt)) {\n throw new MfaError('invalid_response', `Invalid expires_at: ${value}`);\n }\n return expiresAt;\n}\n\n/**\n * Parses passkey creation data embedded in an enrollment response.\n *\n * @param value - JSON-encoded creation options.\n * @returns Validated public-key creation options.\n */\nexport function parsePasskeyCreateData(value: string): PasskeyCreationOptions {\n try {\n const parsed: unknown = JSON.parse(value);\n assertValidMfaResponse(parsed, PasskeyCreateDataStruct);\n return parsed.publicKey;\n } catch (error) {\n if (error instanceof MfaError) {\n throw error;\n }\n const message = toErrorMessage(error);\n throw new MfaError('invalid_response', message);\n }\n}\n\n/**\n * Parses passkey request data embedded in a verification response.\n *\n * @param value - JSON-encoded request options.\n * @returns Validated public-key request options.\n */\nexport function parsePasskeyRequestData(value: string): PasskeyRequestOptions {\n try {\n const parsed: unknown = JSON.parse(value);\n assertValidMfaResponse(parsed, PasskeyRequestDataStruct);\n return parsed.publicKey;\n } catch (error) {\n if (error instanceof MfaError) {\n throw error;\n }\n const message = toErrorMessage(error);\n throw new MfaError('invalid_response', message);\n }\n}\n\n/**\n * Reads a `Retry-After` header as a delay. The human-readable error message is\n * deliberately not parsed: the API documents it as unstable.\n *\n * @param response - The throttled response.\n * @returns The delay in milliseconds, or undefined without a usable header.\n */\nfunction parseRetryAfter(response: Response): number | undefined {\n const header = response.headers.get('Retry-After');\n if (!header) {\n return undefined;\n }\n const seconds = Number(header);\n if (Number.isInteger(seconds)) {\n return Math.max(0, seconds * 1000);\n }\n const date = Date.parse(header);\n return Number.isNaN(date) ? undefined : Math.max(0, date - Date.now());\n}\n\n/**\n * Reads and validates the JSON error body of a failed MFA request.\n *\n * When the body parses as JSON but does not match the documented error\n * shape, a `message` field is salvaged if present so callers still get a\n * useful diagnostic instead of a content-free fallback.\n *\n * @param response - The failed response.\n * @returns The validated error body, a best-effort salvage of it, or\n * undefined when the body could not be parsed as JSON at all.\n */\ntype MfaErrorBody = {\n code?: string;\n message: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n retry_after_seconds?: number;\n};\n\n/**\n * Prefers the documented `retry_after_seconds` error field over the\n * `Retry-After` header.\n *\n * @param body - The parsed error body, if any.\n * @param response - The throttled response.\n * @returns The delay in milliseconds, or undefined when neither is usable.\n */\nfunction resolveRetryAfterMs(\n body: MfaErrorBody | undefined,\n response: Response,\n): number | undefined {\n return body?.retry_after_seconds === undefined\n ? parseRetryAfter(response)\n : body.retry_after_seconds * 1000;\n}\n\nasync function readErrorBody(\n response: Response,\n): Promise<MfaErrorBody | undefined> {\n let body: unknown;\n try {\n body = await response.json();\n } catch {\n return undefined;\n }\n\n try {\n assertValidMfaResponse(body, MfaErrorResponseStruct);\n return body;\n } catch {\n const message = asRecord(body)?.message;\n return typeof message === 'string' ? { message } : undefined;\n }\n}\n\nasync function throwMfaError(\n response: Response,\n errorPrefix: string,\n): Promise<never> {\n const { status } = response;\n const body = await readErrorBody(response);\n const message = `${errorPrefix}: ${body?.message ?? `HTTP ${status}`}`;\n\n // Status-only classification first: gateways and load balancers answer\n // 401/429/502 without the service's JSON body, and the caller still needs\n // to invalidate its session, honour Retry-After, or back off.\n if (status === HTTP_STATUS_CODES.UNAUTHORIZED) {\n throw new MfaError('authentication_required', message, { status });\n }\n\n const code = body?.code;\n switch (code) {\n case 'credential_already_enrolled':\n case 'email_already_enrolled':\n case 'totp_already_enrolled':\n case 'email_socially_verified':\n throw new CredentialAlreadyEnrolledError(code, message, status);\n case 'credential_not_enrolled':\n throw new CredentialNotEnrolledError(message, status);\n case 'aal2_required':\n throw new StepUpRequiredError(message, status);\n case 'flow_expired':\n case 'invalid_flow':\n throw new MfaFlowExpiredError(code, message, status);\n case 'mfa_identity_missing':\n throw new MfaIdentityMissingError(message, status);\n case 'invalid_code':\n case 'invalid_attestation':\n case 'invalid_assertion':\n throw new MfaVerificationFailedError(code, message, status);\n case 'too_many_attempts':\n throw new TooManyAttemptsError(message, status);\n case 'max_passkeys_reached':\n throw new MaxPasskeysReachedError(message, status);\n case 'max_identifiers_reached':\n throw new MaxIdentifiersReachedError(message, status);\n case 'otp_resend_cooldown':\n throw new OtpResendCooldownError(\n message,\n resolveRetryAfterMs(body, response),\n status,\n );\n case 'kratos_unavailable':\n throw new MfaUnavailableError(message, status);\n default:\n break;\n }\n\n if (status === HTTP_STATUS_CODES.TOO_MANY_REQUESTS) {\n throw new MfaRateLimitedError(\n message,\n resolveRetryAfterMs(body, response),\n status,\n );\n }\n if (status === HTTP_STATUS_CODES.BAD_GATEWAY) {\n throw new MfaUnavailableError(message, status);\n }\n if (!body) {\n throw new MfaError(\n 'invalid_response',\n `${errorPrefix}: Unexpected error response (HTTP ${status})`,\n { status },\n );\n }\n throw new MfaError(code ?? 'server_error', message, { status });\n}\n\nasync function requestJson(\n url: string,\n accessToken: string,\n init?: { method?: 'GET' | 'POST'; body?: Json },\n): Promise<Json> {\n let response: Response;\n try {\n response = await fetch(url, {\n method: init?.method ?? 'GET',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n ...(init?.body === undefined\n ? {}\n : { 'Content-Type': 'application/json' }),\n },\n ...(init?.body === undefined ? {} : { body: JSON.stringify(init.body) }),\n });\n } catch (error) {\n const message = toErrorMessage(error);\n throw new MfaUnavailableError(`MFA request failed: ${message}`);\n }\n\n if (!response.ok) {\n return await throwMfaError(response, 'MFA request failed');\n }\n\n try {\n return await response.json();\n } catch (error) {\n const message = toErrorMessage(error);\n throw new MfaError('invalid_response', message, {\n status: response.status,\n });\n }\n}\n\n/**\n * Begins enrollment of an MFA credential.\n *\n * @param env - Authentication environment.\n * @param accessToken - Primary profile access token.\n * @param body - Enrollment request.\n * @returns Validated enrollment flow data.\n */\nexport async function mfaEnroll(\n env: Env,\n accessToken: string,\n body: MfaEnrollRequest,\n): Promise<EnrollmentServiceResult> {\n const json = await requestJson(MFA_ENROLL_URL(env), accessToken, {\n method: 'POST',\n body,\n });\n assertValidMfaResponse(json, MfaEnrollResponseStruct);\n\n return {\n flowId: json.flow_id,\n expiresAt: parseExpiresAt(json.expires_at),\n ...(json.passkey_create_data\n ? { publicKey: parsePasskeyCreateData(json.passkey_create_data) }\n : {}),\n ...(json.totp_secret && json.totp_qr\n ? {\n totp: {\n secret: json.totp_secret,\n qrCode: json.totp_qr,\n setupUri: buildTotpSetupUri(json.totp_secret),\n },\n }\n : {}),\n };\n}\n\n/**\n * Completes enrollment of an MFA credential.\n *\n * @param env - Authentication environment.\n * @param accessToken - Primary profile access token.\n * @param params - Flow identifier and enrollment proof.\n * @returns The assertion JWT proving the enrolled credential, and its lifetime\n * in seconds.\n */\nexport async function mfaEnrollComplete(\n env: Env,\n accessToken: string,\n params: EnrollmentCompletionParams,\n): Promise<MfaVerificationAssertion> {\n let body: MfaEnrollCompleteRequest = {\n credential_type: params.credential_type,\n flow_id: params.flow_id,\n ...(params.otp_code ? { otp_code: params.otp_code } : {}),\n };\n if (params.passkey_attestation) {\n assertValidMfaRequest(\n params.passkey_attestation,\n RegistrationResponseJSONStruct,\n );\n body = {\n ...body,\n passkey_attestation: JSON.stringify(params.passkey_attestation),\n };\n }\n\n const json = await requestJson(MFA_ENROLL_COMPLETE_URL(env), accessToken, {\n method: 'POST',\n body,\n });\n assertValidMfaResponse(json, MfaEnrollCompleteResponseStruct);\n return { token: json.token, expiresIn: json.expires_in };\n}\n\n/**\n * Begins verification with an enrolled credential.\n *\n * @param env - Authentication environment.\n * @param accessToken - Primary profile access token.\n * @param body - Verification request.\n * @returns Validated verification flow data.\n */\nexport async function mfaVerify(\n env: Env,\n accessToken: string,\n body: MfaVerifyRequest,\n): Promise<VerificationServiceResult> {\n const json = await requestJson(MFA_VERIFY_URL(env), accessToken, {\n method: 'POST',\n body,\n });\n assertValidMfaResponse(json, MfaVerifyResponseStruct);\n\n return {\n flowId: json.flow_id,\n expiresAt: parseExpiresAt(json.expires_at),\n ...(json.passkey_request_data\n ? { publicKey: parsePasskeyRequestData(json.passkey_request_data) }\n : {}),\n };\n}\n\n/**\n * Completes verification with an enrolled credential.\n *\n * @param env - Authentication environment.\n * @param accessToken - Primary profile access token.\n * @param params - Flow identifier and verification proof.\n * @returns The assertion JWT and its lifetime in seconds.\n */\nexport async function mfaVerifyComplete(\n env: Env,\n accessToken: string,\n params: VerificationCompletionParams,\n): Promise<MfaVerificationAssertion> {\n let body: MfaVerifyCompleteRequest = {\n credential_type: params.credential_type,\n flow_id: params.flow_id,\n ...(params.otp_code ? { otp_code: params.otp_code } : {}),\n };\n if (params.passkey_assertion) {\n assertValidMfaRequest(\n params.passkey_assertion,\n AuthenticationResponseJSONStruct,\n );\n body = {\n ...body,\n passkey_assertion: JSON.stringify(params.passkey_assertion),\n };\n }\n\n const json = await requestJson(MFA_VERIFY_COMPLETE_URL(env), accessToken, {\n method: 'POST',\n body,\n });\n assertValidMfaResponse(json, MfaVerifyCompleteResponseStruct);\n return { token: json.token, expiresIn: json.expires_in };\n}\n\nfunction isSupportedStatus(status: string): status is MfaCredentialStatus {\n return status === 'active' || status === 'pending';\n}\n\n/**\n * Maps a server credential to its public controller representation.\n *\n * Unknown credential types or statuses are dropped so the server can extend\n * either without invalidating the whole list.\n *\n * @param credential - Validated server credential.\n * @returns A supported credential, or null when it cannot be represented.\n */\nexport function toEnrolledCredential(\n credential: MfaCredential,\n): EnrolledCredential | null {\n const { credential_type: type, status } = credential;\n if (!isSupportedStatus(status)) {\n log.warn(`Ignoring MFA credential with unsupported status: ${status}`);\n return null;\n }\n\n const enrolledAt = parseCredentialDate('enrolled_at', credential.enrolled_at);\n const lastUsedAt = parseCredentialDate(\n 'last_used_at',\n credential.last_used_at,\n );\n const base = {\n status,\n ...(enrolledAt === undefined ? {} : { enrolledAt }),\n ...(lastUsedAt === undefined ? {} : { lastUsedAt }),\n };\n\n if (type === 'passkey') {\n return {\n type,\n ...base,\n ...(credential.passkey?.display_name\n ? { displayName: credential.passkey.display_name }\n : {}),\n };\n }\n\n if (type === 'email_otp') {\n // The API marks the address optional, so a row without one is kept.\n const address = credential.email?.address;\n return {\n type,\n ...base,\n ...(address === undefined ? {} : { email: address }),\n // The spec marks `verified` optional; an active row is verified.\n verified: credential.email?.verified ?? status === 'active',\n };\n }\n\n if (type === 'totp') {\n return { type, ...base };\n }\n\n log.warn(`Ignoring unsupported or incomplete MFA credential: ${type}`);\n return null;\n}\n\n/**\n * Gets the credentials enrolled on the canonical profile.\n *\n * @param env - Authentication environment.\n * @param accessToken - Primary profile access token.\n * @returns Supported enrolled credentials.\n */\nexport async function getMfaCredentials(\n env: Env,\n accessToken: string,\n): Promise<EnrolledCredential[]> {\n const json = await requestJson(MFA_CREDENTIALS_URL(env), accessToken);\n assertValidMfaResponse(json, MfaCredentialsResponseStruct);\n return json.credentials\n .map(toEnrolledCredential)\n .filter((credential): credential is EnrolledCredential =>\n Boolean(credential),\n );\n}\n"]}
@@ -35,22 +35,27 @@ export type MfaVerifyCompleteRequest = {
35
35
  passkey_assertion?: string;
36
36
  otp_code?: string;
37
37
  };
38
- export type EnrolledCredential = {
39
- type: 'passkey';
38
+ type EnrolledCredentialBase = {
40
39
  status: MfaCredentialStatus;
40
+ /** Epoch milliseconds, when the server sent a valid date. */
41
41
  enrolledAt?: number;
42
+ /** Epoch milliseconds of the last verification, when the server sent one. */
43
+ lastUsedAt?: number;
44
+ };
45
+ export type EnrolledCredential = EnrolledCredentialBase & ({
46
+ type: 'passkey';
42
47
  displayName?: string;
43
48
  } | {
44
49
  type: 'email_otp';
45
- status: MfaCredentialStatus;
46
- enrolledAt?: number;
47
50
  /**
48
- * Absent when the server lists an email method without its address; the
49
- * API marks the address optional.
51
+ * Absent when the server lists an email method without its address;
52
+ * the API marks the address optional.
50
53
  */
51
54
  email?: string;
52
55
  verified: boolean;
53
- };
56
+ } | {
57
+ type: 'totp';
58
+ });
54
59
  /**
55
60
  * Caller-supplied context attached to MFA trace spans. `operation` names the
56
61
  * client flow that needs the credential (for example `money.signTransaction`).
@@ -58,38 +63,55 @@ export type EnrolledCredential = {
58
63
  export type TokenReason = {
59
64
  operation: string;
60
65
  };
61
- export type EnrollmentChallenge = {
62
- type: 'passkey';
66
+ /** Fields every enrollment or verification challenge carries. */
67
+ type MfaChallengeBase = {
68
+ /** Identifier to send back when completing the flow. */
63
69
  flowId: string;
70
+ /** Epoch milliseconds after which the flow can no longer be completed. */
64
71
  expiresAt: number;
72
+ };
73
+ export type EnrollmentChallenge = MfaChallengeBase & ({
74
+ type: 'passkey';
65
75
  publicKey: PublicKeyCredentialCreationOptionsJSON;
66
76
  } | {
67
77
  type: 'email_otp';
68
- flowId: string;
69
- expiresAt: number;
70
- };
78
+ } | {
79
+ type: 'totp';
80
+ /**
81
+ * Base32 secret for the user's authenticator app, for manual entry or
82
+ * an `otpauth://` link. Never log or persist it.
83
+ */
84
+ secret: string;
85
+ /**
86
+ * PNG data URL of the QR code encoding the secret; render it as-is.
87
+ * Never log or persist it.
88
+ */
89
+ qrCode: string;
90
+ /**
91
+ * `otpauth://` link that opens an authenticator app on this device
92
+ * with the account to add, since a phone cannot scan its own screen.
93
+ * Contains the secret: never log or persist it.
94
+ */
95
+ setupUri: string;
96
+ });
71
97
  export type EnrollmentProof = {
72
98
  type: 'passkey';
73
99
  attestation: RegistrationResponseJSON;
74
100
  } | {
75
- type: 'email_otp';
101
+ type: 'email_otp' | 'totp';
76
102
  code: string;
77
103
  };
78
- export type VerificationChallenge = {
104
+ export type VerificationChallenge = MfaChallengeBase & ({
79
105
  type: 'passkey';
80
- flowId: string;
81
- expiresAt: number;
82
106
  publicKey: PublicKeyCredentialRequestOptionsJSON;
83
107
  } | {
84
- type: 'email_otp';
85
- flowId: string;
86
- expiresAt: number;
87
- };
108
+ type: 'email_otp' | 'totp';
109
+ });
88
110
  export type VerificationProof = {
89
111
  type: 'passkey';
90
112
  assertion: AuthenticationResponseJSON;
91
113
  } | {
92
- type: 'email_otp';
114
+ type: 'email_otp' | 'totp';
93
115
  code: string;
94
116
  };
95
117
  export type VerificationToken = {
@@ -135,5 +157,5 @@ export type CompleteVerificationRequest = {
135
157
  export type GetVerificationTokenRequest = {
136
158
  maxSessionAgeMs?: number;
137
159
  };
138
- export type MfaErrorCode = 'max_passkeys_reached' | 'max_identifiers_reached' | 'email_already_enrolled' | 'credential_already_enrolled' | 'credential_not_enrolled' | 'email_socially_verified' | 'mfa_identity_missing' | 'multi_primary_srp' | 'aal2_required' | 'otp_resend_cooldown' | 'rate_limited' | 'kratos_unavailable' | 'flow_expired' | 'invalid_flow' | 'invalid_attestation' | 'invalid_code' | 'invalid_assertion' | 'too_many_attempts' | 'verification_token_invalid' | 'authentication_required' | 'server_error' | 'invalid_response' | 'invalid_request';
160
+ export type MfaErrorCode = 'max_passkeys_reached' | 'max_identifiers_reached' | 'email_already_enrolled' | 'totp_already_enrolled' | 'credential_already_enrolled' | 'credential_not_enrolled' | 'email_socially_verified' | 'mfa_identity_missing' | 'multi_primary_srp' | 'aal2_required' | 'otp_resend_cooldown' | 'rate_limited' | 'kratos_unavailable' | 'flow_expired' | 'invalid_flow' | 'invalid_attestation' | 'invalid_code' | 'invalid_assertion' | 'too_many_attempts' | 'verification_token_invalid' | 'authentication_required' | 'server_error' | 'invalid_response' | 'invalid_request';
139
161
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/sdk/authentication-jwt-bearer/mfa/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/sdk/authentication-jwt-bearer/mfa/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/sdk/authentication-jwt-bearer/mfa/types.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAE,oBAAoB,EAAE,CAAC","sourcesContent":["import type { Infer } from '@metamask/superstruct';\n\nimport type {\n AuthenticationResponseJSONStruct,\n MfaCredentialStruct,\n MfaCredentialsResponseStruct,\n MfaEmailDetailStruct,\n MfaEnrollCompleteResponseStruct,\n MfaEnrollResponseStruct,\n MfaPasskeyDetailStruct,\n MfaVerifyCompleteResponseStruct,\n MfaVerifyResponseStruct,\n PublicKeyCredentialCreationOptionsJSONStruct,\n PublicKeyCredentialRequestOptionsJSONStruct,\n RegistrationResponseJSONStruct,\n} from './schemas.js';\nimport { MFA_CREDENTIAL_TYPES } from './schemas.js';\n\nexport { MFA_CREDENTIAL_TYPES };\n\nexport type MfaCredentialType = (typeof MFA_CREDENTIAL_TYPES)[number];\n\nexport type MfaCredentialStatus = 'active' | 'pending';\n\nexport type PublicKeyCredentialCreationOptionsJSON = Infer<\n typeof PublicKeyCredentialCreationOptionsJSONStruct\n>;\n\nexport type PublicKeyCredentialRequestOptionsJSON = Infer<\n typeof PublicKeyCredentialRequestOptionsJSONStruct\n>;\n\nexport type RegistrationResponseJSON = Infer<\n typeof RegistrationResponseJSONStruct\n>;\n\nexport type AuthenticationResponseJSON = Infer<\n typeof AuthenticationResponseJSONStruct\n>;\n\nexport type MfaEnrollResponse = Infer<typeof MfaEnrollResponseStruct>;\n\nexport type MfaEnrollCompleteResponse = Infer<\n typeof MfaEnrollCompleteResponseStruct\n>;\n\nexport type MfaVerifyResponse = Infer<typeof MfaVerifyResponseStruct>;\n\nexport type MfaVerifyCompleteResponse = Infer<\n typeof MfaVerifyCompleteResponseStruct\n>;\n\nexport type MfaCredentialsResponse = Infer<typeof MfaCredentialsResponseStruct>;\n\nexport type MfaCredential = Infer<typeof MfaCredentialStruct>;\n\nexport type MfaPasskeyDetail = Infer<typeof MfaPasskeyDetailStruct>;\n\nexport type MfaEmailDetail = Infer<typeof MfaEmailDetailStruct>;\n\nexport type MfaEnrollRequest = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n credential_type: MfaCredentialType;\n identifier?: string;\n};\n\nexport type MfaEnrollCompleteRequest = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n credential_type: MfaCredentialType;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n flow_id: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n otp_code?: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n passkey_attestation?: string;\n};\n\nexport type MfaVerifyRequest = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n credential_type: MfaCredentialType;\n};\n\nexport type MfaVerifyCompleteRequest = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n credential_type: MfaCredentialType;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n flow_id: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n passkey_assertion?: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n otp_code?: string;\n};\n\nexport type EnrolledCredential =\n | {\n type: 'passkey';\n status: MfaCredentialStatus;\n enrolledAt?: number;\n displayName?: string;\n }\n | {\n type: 'email_otp';\n status: MfaCredentialStatus;\n enrolledAt?: number;\n /**\n * Absent when the server lists an email method without its address; the\n * API marks the address optional.\n */\n email?: string;\n verified: boolean;\n };\n\n/**\n * Caller-supplied context attached to MFA trace spans. `operation` names the\n * client flow that needs the credential (for example `money.signTransaction`).\n */\nexport type TokenReason = {\n operation: string;\n};\n\nexport type EnrollmentChallenge =\n | {\n type: 'passkey';\n flowId: string;\n expiresAt: number;\n publicKey: PublicKeyCredentialCreationOptionsJSON;\n }\n | {\n type: 'email_otp';\n flowId: string;\n expiresAt: number;\n };\n\nexport type EnrollmentProof =\n | {\n type: 'passkey';\n attestation: RegistrationResponseJSON;\n }\n | {\n type: 'email_otp';\n code: string;\n };\n\nexport type VerificationChallenge =\n | {\n type: 'passkey';\n flowId: string;\n expiresAt: number;\n publicKey: PublicKeyCredentialRequestOptionsJSON;\n }\n | {\n type: 'email_otp';\n flowId: string;\n expiresAt: number;\n };\n\nexport type VerificationProof =\n | {\n type: 'passkey';\n assertion: AuthenticationResponseJSON;\n }\n | {\n type: 'email_otp';\n code: string;\n };\n\nexport type VerificationToken = {\n accessToken: string;\n expiresIn: number;\n obtainedAt: number;\n claims: {\n sub: string;\n /**\n * Methods the verification used. Usually an `MfaCredentialType`, but the\n * server may report other method names.\n */\n amr: (MfaCredentialType | (string & Record<never, never>))[];\n exp: number;\n };\n};\n\nexport type BeginEnrollmentRequest = {\n type: MfaCredentialType;\n email?: string;\n reason: TokenReason;\n /**\n * Maximum age, in milliseconds, of a verification session that may authorize\n * this enrollment. Defaults to `ENROLLMENT_MAX_SESSION_AGE_MS`. A setup flow\n * that proved a factor itself may pass the time elapsed since it started.\n * Zero never uses the session.\n */\n maxSessionAgeMs?: number;\n};\n\nexport type CompleteEnrollmentRequest = {\n flowId: string;\n proof: EnrollmentProof;\n reason: TokenReason;\n};\n\nexport type BeginVerificationRequest = {\n type: MfaCredentialType;\n reason: TokenReason;\n};\n\nexport type CompleteVerificationRequest = {\n flowId: string;\n proof: VerificationProof;\n reason: TokenReason;\n};\n\nexport type GetVerificationTokenRequest = {\n maxSessionAgeMs?: number;\n};\n\nexport type MfaErrorCode =\n | 'max_passkeys_reached'\n | 'max_identifiers_reached'\n | 'email_already_enrolled'\n | 'credential_already_enrolled'\n | 'credential_not_enrolled'\n | 'email_socially_verified'\n | 'mfa_identity_missing'\n | 'multi_primary_srp'\n | 'aal2_required'\n | 'otp_resend_cooldown'\n | 'rate_limited'\n | 'kratos_unavailable'\n | 'flow_expired'\n | 'invalid_flow'\n | 'invalid_attestation'\n | 'invalid_code'\n | 'invalid_assertion'\n | 'too_many_attempts'\n | 'verification_token_invalid'\n | 'authentication_required'\n | 'server_error'\n | 'invalid_response'\n | 'invalid_request';\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/sdk/authentication-jwt-bearer/mfa/types.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAE,oBAAoB,EAAE,CAAC","sourcesContent":["import type { Infer } from '@metamask/superstruct';\n\nimport type {\n AuthenticationResponseJSONStruct,\n MfaCredentialStruct,\n MfaCredentialsResponseStruct,\n MfaEmailDetailStruct,\n MfaEnrollCompleteResponseStruct,\n MfaEnrollResponseStruct,\n MfaPasskeyDetailStruct,\n MfaVerifyCompleteResponseStruct,\n MfaVerifyResponseStruct,\n PublicKeyCredentialCreationOptionsJSONStruct,\n PublicKeyCredentialRequestOptionsJSONStruct,\n RegistrationResponseJSONStruct,\n} from './schemas.js';\nimport { MFA_CREDENTIAL_TYPES } from './schemas.js';\n\nexport { MFA_CREDENTIAL_TYPES };\n\nexport type MfaCredentialType = (typeof MFA_CREDENTIAL_TYPES)[number];\n\nexport type MfaCredentialStatus = 'active' | 'pending';\n\nexport type PublicKeyCredentialCreationOptionsJSON = Infer<\n typeof PublicKeyCredentialCreationOptionsJSONStruct\n>;\n\nexport type PublicKeyCredentialRequestOptionsJSON = Infer<\n typeof PublicKeyCredentialRequestOptionsJSONStruct\n>;\n\nexport type RegistrationResponseJSON = Infer<\n typeof RegistrationResponseJSONStruct\n>;\n\nexport type AuthenticationResponseJSON = Infer<\n typeof AuthenticationResponseJSONStruct\n>;\n\nexport type MfaEnrollResponse = Infer<typeof MfaEnrollResponseStruct>;\n\nexport type MfaEnrollCompleteResponse = Infer<\n typeof MfaEnrollCompleteResponseStruct\n>;\n\nexport type MfaVerifyResponse = Infer<typeof MfaVerifyResponseStruct>;\n\nexport type MfaVerifyCompleteResponse = Infer<\n typeof MfaVerifyCompleteResponseStruct\n>;\n\nexport type MfaCredentialsResponse = Infer<typeof MfaCredentialsResponseStruct>;\n\nexport type MfaCredential = Infer<typeof MfaCredentialStruct>;\n\nexport type MfaPasskeyDetail = Infer<typeof MfaPasskeyDetailStruct>;\n\nexport type MfaEmailDetail = Infer<typeof MfaEmailDetailStruct>;\n\nexport type MfaEnrollRequest = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n credential_type: MfaCredentialType;\n identifier?: string;\n};\n\nexport type MfaEnrollCompleteRequest = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n credential_type: MfaCredentialType;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n flow_id: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n otp_code?: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n passkey_attestation?: string;\n};\n\nexport type MfaVerifyRequest = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n credential_type: MfaCredentialType;\n};\n\nexport type MfaVerifyCompleteRequest = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n credential_type: MfaCredentialType;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n flow_id: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n passkey_assertion?: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n otp_code?: string;\n};\n\ntype EnrolledCredentialBase = {\n status: MfaCredentialStatus;\n /** Epoch milliseconds, when the server sent a valid date. */\n enrolledAt?: number;\n /** Epoch milliseconds of the last verification, when the server sent one. */\n lastUsedAt?: number;\n};\n\nexport type EnrolledCredential = EnrolledCredentialBase &\n (\n | {\n type: 'passkey';\n displayName?: string;\n }\n | {\n type: 'email_otp';\n /**\n * Absent when the server lists an email method without its address;\n * the API marks the address optional.\n */\n email?: string;\n verified: boolean;\n }\n | {\n type: 'totp';\n }\n );\n\n/**\n * Caller-supplied context attached to MFA trace spans. `operation` names the\n * client flow that needs the credential (for example `money.signTransaction`).\n */\nexport type TokenReason = {\n operation: string;\n};\n\n/** Fields every enrollment or verification challenge carries. */\ntype MfaChallengeBase = {\n /** Identifier to send back when completing the flow. */\n flowId: string;\n /** Epoch milliseconds after which the flow can no longer be completed. */\n expiresAt: number;\n};\n\nexport type EnrollmentChallenge = MfaChallengeBase &\n (\n | {\n type: 'passkey';\n publicKey: PublicKeyCredentialCreationOptionsJSON;\n }\n | {\n type: 'email_otp';\n }\n | {\n type: 'totp';\n /**\n * Base32 secret for the user's authenticator app, for manual entry or\n * an `otpauth://` link. Never log or persist it.\n */\n secret: string;\n /**\n * PNG data URL of the QR code encoding the secret; render it as-is.\n * Never log or persist it.\n */\n qrCode: string;\n /**\n * `otpauth://` link that opens an authenticator app on this device\n * with the account to add, since a phone cannot scan its own screen.\n * Contains the secret: never log or persist it.\n */\n setupUri: string;\n }\n );\n\nexport type EnrollmentProof =\n | {\n type: 'passkey';\n attestation: RegistrationResponseJSON;\n }\n | {\n type: 'email_otp' | 'totp';\n code: string;\n };\n\nexport type VerificationChallenge = MfaChallengeBase &\n (\n | {\n type: 'passkey';\n publicKey: PublicKeyCredentialRequestOptionsJSON;\n }\n | {\n type: 'email_otp' | 'totp';\n }\n );\n\nexport type VerificationProof =\n | {\n type: 'passkey';\n assertion: AuthenticationResponseJSON;\n }\n | {\n type: 'email_otp' | 'totp';\n code: string;\n };\n\nexport type VerificationToken = {\n accessToken: string;\n expiresIn: number;\n obtainedAt: number;\n claims: {\n sub: string;\n /**\n * Methods the verification used. Usually an `MfaCredentialType`, but the\n * server may report other method names.\n */\n amr: (MfaCredentialType | (string & Record<never, never>))[];\n exp: number;\n };\n};\n\nexport type BeginEnrollmentRequest = {\n type: MfaCredentialType;\n email?: string;\n reason: TokenReason;\n /**\n * Maximum age, in milliseconds, of a verification session that may authorize\n * this enrollment. Defaults to `ENROLLMENT_MAX_SESSION_AGE_MS`. A setup flow\n * that proved a factor itself may pass the time elapsed since it started.\n * Zero never uses the session.\n */\n maxSessionAgeMs?: number;\n};\n\nexport type CompleteEnrollmentRequest = {\n flowId: string;\n proof: EnrollmentProof;\n reason: TokenReason;\n};\n\nexport type BeginVerificationRequest = {\n type: MfaCredentialType;\n reason: TokenReason;\n};\n\nexport type CompleteVerificationRequest = {\n flowId: string;\n proof: VerificationProof;\n reason: TokenReason;\n};\n\nexport type GetVerificationTokenRequest = {\n maxSessionAgeMs?: number;\n};\n\nexport type MfaErrorCode =\n | 'max_passkeys_reached'\n | 'max_identifiers_reached'\n | 'email_already_enrolled'\n | 'totp_already_enrolled'\n | 'credential_already_enrolled'\n | 'credential_not_enrolled'\n | 'email_socially_verified'\n | 'mfa_identity_missing'\n | 'multi_primary_srp'\n | 'aal2_required'\n | 'otp_resend_cooldown'\n | 'rate_limited'\n | 'kratos_unavailable'\n | 'flow_expired'\n | 'invalid_flow'\n | 'invalid_attestation'\n | 'invalid_code'\n | 'invalid_assertion'\n | 'too_many_attempts'\n | 'verification_token_invalid'\n | 'authentication_required'\n | 'server_error'\n | 'invalid_response'\n | 'invalid_request';\n"]}
@@ -1,12 +1,13 @@
1
1
  import type { Env, Platform } from '../../shared/env.js';
2
2
  import type { MetaMetricsAuth } from '../../shared/types/services.js';
3
- import type { AccessToken, LoginIdentifierType, OidcTokenAudience, OidcTokenClaims, PairSocialIdentifierParams, ProfileAlias, ProfileIdentifier, UserProfile, UserProfileLineage } from './types.js';
3
+ import type { AccessToken, LoginIdentifierType, OidcTokenAudience, OidcTokenClaims, PairSocialIdentifierParams, ProfileAlias, ProfileIdentifier, SocialLoginParams, UserProfile, UserProfileLineage } from './types.js';
4
4
  import { AuthType } from './types.js';
5
5
  export declare const NONCE_URL: (env: Env) => string;
6
6
  export declare const PAIR_IDENTIFIERS: (env: Env) => string;
7
7
  export declare const OIDC_TOKEN_URL: (env: Env) => string;
8
8
  export declare const SRP_LOGIN_URL: (env: Env) => string;
9
9
  export declare const SIWE_LOGIN_URL: (env: Env) => string;
10
+ export declare const SOCIAL_LOGIN_URL: (env: Env) => string;
10
11
  export declare const PAIR_PROFILES_URL: (env: Env) => string;
11
12
  export declare const PAIR_SOCIAL_IDENTIFIER_URL: (env: Env) => string;
12
13
  export declare const PROFILE_LINEAGE_URL: (env: Env) => string;
@@ -96,6 +97,16 @@ type Authentication = {
96
97
  * @returns Authentication Token
97
98
  */
98
99
  export declare function authenticate(rawMessage: string, signature: string, authType: AuthType, env: Env, metametrics?: MetaMetricsAuth, identifierType?: LoginIdentifierType): Promise<Authentication>;
100
+ /**
101
+ * Service to log in with a Google/Apple/Telegram social token
102
+ * (`POST /api/v2/social/login`). The identifier must already be paired to a
103
+ * profile; 404 throws {@link SocialIdentifierNotPairedError}.
104
+ *
105
+ * @param params - Social identifier type and social JWT
106
+ * @param env - server environment
107
+ * @returns Authentication Token for the canonical profile
108
+ */
109
+ export declare function socialLogin(params: SocialLoginParams, env: Env): Promise<Authentication>;
99
110
  /**
100
111
  * Service to get the Profile Lineage
101
112
  *
@@ -1 +1 @@
1
- {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/services.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/services.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { getEnvUrls, getOidcClientId } from '../../shared/env.js';
2
2
  import { HTTP_STATUS_CODES } from '../constants.js';
3
- import { NonceRetrievalError, EmailRequiredError, PairConflictError, PairError, SignInError, ValidationError, RateLimitedError, } from '../errors.js';
3
+ import { NonceRetrievalError, EmailRequiredError, PairConflictError, PairError, SignInError, SocialIdentifierNotPairedError, ValidationError, RateLimitedError, } from '../errors.js';
4
4
  import { validatePairResponse } from '../utils/validate-pair-response.js';
5
5
  import { AuthType } from './types.js';
6
6
  /**
@@ -105,6 +105,7 @@ export const PAIR_IDENTIFIERS = (env) => `${getEnvUrls(env).authApiUrl}/api/v2/i
105
105
  export const OIDC_TOKEN_URL = (env) => `${getEnvUrls(env).oidcApiUrl}/oauth2/token`;
106
106
  export const SRP_LOGIN_URL = (env) => `${getEnvUrls(env).authApiUrl}/api/v2/srp/login`;
107
107
  export const SIWE_LOGIN_URL = (env) => `${getEnvUrls(env).authApiUrl}/api/v2/siwe/login`;
108
+ export const SOCIAL_LOGIN_URL = (env) => `${getEnvUrls(env).authApiUrl}/api/v2/social/login`;
108
109
  export const PAIR_PROFILES_URL = (env) => `${getEnvUrls(env).authApiUrl}/api/v2/profile/pair`;
109
110
  export const PAIR_SOCIAL_IDENTIFIER_URL = (env) => `${getEnvUrls(env).authApiUrl}/api/v2/profile/pair/identifier`;
110
111
  export const PROFILE_LINEAGE_URL = (env) => `${getEnvUrls(env).authApiUrl}/api/v2/profile/lineage`;
@@ -306,6 +307,27 @@ export async function authorizeOIDC(jwtToken, env, platform) {
306
307
  return await throwServiceError(error, 'Failed to get access token', SignInError);
307
308
  }
308
309
  }
310
+ /* eslint-enable @typescript-eslint/naming-convention */
311
+ /**
312
+ * Maps the API's `Authentication` response, shared by the login endpoints.
313
+ *
314
+ * @param loginResponse - The parsed response body.
315
+ * @returns The authentication token, profile and aliases.
316
+ */
317
+ function parseAuthentication(loginResponse) {
318
+ return {
319
+ token: loginResponse.token,
320
+ expiresIn: loginResponse.expires_in,
321
+ profile: {
322
+ identifierId: loginResponse.profile.identifier_id,
323
+ metaMetricsId: loginResponse.profile.metametrics_id,
324
+ profileId: loginResponse.profile.profile_id,
325
+ canonicalProfileId: loginResponse.profile.profile_id,
326
+ pairedIdentifierIds: loginResponse.profile.paired_identifier_ids,
327
+ },
328
+ profileAliases: parseProfileAliases(loginResponse.profile_aliases ?? []),
329
+ };
330
+ }
309
331
  /**
310
332
  * Service to Authenticate/Login a user via SIWE or SRP derived key.
311
333
  *
@@ -347,24 +369,44 @@ export async function authenticate(rawMessage, signature, authType, env, metamet
347
369
  if (!response.ok) {
348
370
  return await throwServiceError(response, `Failed to login with ${authType}`, SignInError);
349
371
  }
350
- const loginResponse = await response.json();
351
- return {
352
- token: loginResponse.token,
353
- expiresIn: loginResponse.expires_in,
354
- profile: {
355
- identifierId: loginResponse.profile.identifier_id,
356
- metaMetricsId: loginResponse.profile.metametrics_id,
357
- profileId: loginResponse.profile.profile_id,
358
- canonicalProfileId: loginResponse.profile.profile_id,
359
- pairedIdentifierIds: loginResponse.profile.paired_identifier_ids,
360
- },
361
- profileAliases: parseProfileAliases(loginResponse.profile_aliases ?? []),
362
- };
372
+ return parseAuthentication((await response.json()));
363
373
  }
364
374
  catch (error) {
365
375
  return await throwServiceError(error, `Failed to login with ${authType}`, SignInError);
366
376
  }
367
377
  }
378
+ /**
379
+ * Service to log in with a Google/Apple/Telegram social token
380
+ * (`POST /api/v2/social/login`). The identifier must already be paired to a
381
+ * profile; 404 throws {@link SocialIdentifierNotPairedError}.
382
+ *
383
+ * @param params - Social identifier type and social JWT
384
+ * @param env - server environment
385
+ * @returns Authentication Token for the canonical profile
386
+ */
387
+ export async function socialLogin(params, env) {
388
+ const errorPrefix = 'Failed to login with social';
389
+ try {
390
+ const response = await fetch(SOCIAL_LOGIN_URL(env), {
391
+ method: 'POST',
392
+ headers: {
393
+ 'Content-Type': 'application/json',
394
+ Authorization: `Bearer ${params.socialJwt}`,
395
+ },
396
+ body: JSON.stringify({ identifier_type: params.identifierType }),
397
+ });
398
+ if (!response.ok) {
399
+ if (response.status === HTTP_STATUS_CODES.NOT_FOUND) {
400
+ await throwServiceError(response, errorPrefix, SocialIdentifierNotPairedError);
401
+ }
402
+ await throwServiceError(response, errorPrefix, SignInError);
403
+ }
404
+ return parseAuthentication((await response.json()));
405
+ }
406
+ catch (error) {
407
+ return await throwServiceError(error, errorPrefix, SignInError);
408
+ }
409
+ }
368
410
  /**
369
411
  * Service to get the Profile Lineage
370
412
  *