Skip to content

Latest commit

Β 

History

History
3885 lines (2445 loc) Β· 111 KB

api.md

File metadata and controls

3885 lines (2445 loc) Β· 111 KB

Firefox Accounts authentication server API

WARNING: Some of this information is wrong, use it at your own risk. It may be worth verifying things in the source code before acting on anything you read here.

This document provides protocol-level details of the Firefox Accounts auth server API. For a prose description of the client/server protocol and details on how each parameter is derived, see the API design document. For a reference client implementation, see fxa-auth-client.

Overview

URL structure

All requests use URLs of the form:

https://<base-URI>/v1/<endpoint-path>

Note that:

  • All API access must be over a properly-validated HTTPS connection.
  • The URL embeds a version identifier v1. Future revisions of this API may introduce new version numbers.
  • The base URI of the server may be configured on a per-client basis:
    • For a list of development servers see Firefox Accounts deployments on MDN.
    • The canonical URL for Mozilla's hosted Firefox Accounts server is https://api.accounts.firefox.com/v1.

Request format

Requests that require authentication use Hawk request signatures. These endpoints are marked with a πŸ”’ icon. Where the authentication is optional, there will also be a ❓ icon.

All POST requests must have a content-type of application/json with a UTF8-encoded JSON body and must specify the content-length header. Keys and other binary data are included in the JSON as hexadecimal strings.

The following request headers may be specified to influence the behaviour of the server:

  • Accept-Language may be used to localize emails and SMS messages.

Response format

All requests receive a JSON response body with a Content-Type: application/json header and appropriate Content-Length set. The body structure depends on the endpoint returning it.

Successful responses will have an HTTP status code of 200 and a Timestamp header that contains the current server time in seconds since the epoch.

Error responses caused by invalid client behaviour will have an HTTP status code in the 4xx range. Error responses caused by server-side problems will have an HTTP status code in the 5xx range. Failures due to invalid behavior from the client

To simplify error handling for the client, the type of error is indicated by both a defined HTTP status code and an application-specific errno in the body. For example:

{
  "code": 400,  // Matches the HTTP status code
  "errno": 107, // Stable application-level error number
  "error": "Bad Request", // String description of the error type
  "message": "Invalid parameter in request body", // Specific error message
  "info": "https://docs.dev.lcip.og/errors/1234"  // Link to more information
}

Responses for some errors may include additional parameters.

Defined errors

The currently-defined values for code and errno are:

  • code: 400, errno: 100: Incorrect Database Patch Level
  • code: 400, errno: 101: Account already exists
  • code: 400, errno: 102: Unknown account
  • code: 400, errno: 103: Incorrect password
  • code: 400, errno: 104: Unverified account
  • code: 400, errno: 105: Invalid verification code
  • code: 400, errno: 106: Invalid JSON in request body
  • code: 400, errno: 107: Invalid parameter in request body
  • code: 400, errno: 108: Missing parameter in request body
  • code: 401, errno: 109: Invalid request signature
  • code: 401, errno: 110: Invalid authentication token in request signature
  • code: 401, errno: 111: Invalid timestamp in request signature
  • code: 411, errno: 112: Missing content-length header
  • code: 413, errno: 113: Request body too large
  • code: 429, errno: 114: Client has sent too many requests
  • code: 401, errno: 115: Invalid nonce in request signature
  • code: 410, errno: 116: This endpoint is no longer supported
  • code: 400, errno: 120: Incorrect email case
  • code: 400, errno: 123: Unknown device
  • code: 400, errno: 124: Session already registered by another device
  • code: 400, errno: 125: The request was blocked for security reasons
  • code: 400, errno: 126: Account must be reset
  • code: 400, errno: 127: Invalid unblock code
  • code: 400, errno: 129: Invalid phone number
  • code: 400, errno: 130: Invalid region
  • code: 400, errno: 131: Invalid message id
  • code: 500, errno: 132: Message rejected
  • code: 400, errno: 133: Email account sent complaint
  • code: 400, errno: 134: Email account hard bounced
  • code: 400, errno: 135: Email account soft bounced
  • code: 400, errno: 136: Email already exists
  • code: 400, errno: 137: Can not delete primary email
  • code: 400, errno: 138: Unverified session
  • code: 400, errno: 139: Can not add secondary email that is same as your primary
  • code: 400, errno: 140: Email already exists
  • code: 400, errno: 141: Email already exists
  • code: 400, errno: 142: Sign in with this email type is not currently supported
  • code: 400, errno: 143: Unknown email
  • code: 400, errno: 144: Email already exists
  • code: 400, errno: 145: Reset password with this email type is not currently supported
  • code: 400, errno: 146: Invalid signin code
  • code: 400, errno: 147: Can not change primary email to an unverified email
  • code: 400, errno: 148: Can not change primary email to an email that does not belong to this account
  • code: 400, errno: 149: This email can not currently be used to login
  • code: 400, errno: 150: Can not resend email code to an email that does not belong to this account
  • code: 500, errno: 151: Failed to send email
  • code: 422, errno: 151: Failed to send email
  • code: 400, errno: 152: Invalid token verification code
  • code: 400, errno: 153: Expired token verification code
  • code: 400, errno: 154: TOTP token already exists for this account.
  • code: 400, errno: 155: TOTP token not found.
  • code: 400, errno: 156: Recovery code not found.
  • code: 400, errno: 157: Unavailable device command.
  • code: 400, errno: 158: Recovery key not found.
  • code: 400, errno: 159: Recovery key is not valid.
  • code: 400, errno: 160: This request requires two step authentication enabled on your account.
  • code: 400, errno: 161: Recovery key already exists.
  • code: 400, errno: 162: Unknown client_id
  • code: 400, errno: 164: Stale auth timestamp
  • code: 409, errno: 165: Redis WATCH detected a conflicting update
  • code: 400, errno: 166: Not a public client
  • code: 400, errno: 167: Incorrect redirect URI
  • code: 400, errno: 168: Invalid response_type
  • code: 400, errno: 169: Requested scopes are not allowed
  • code: 400, errno: 170: Public clients require PKCE OAuth parameters
  • code: 400, errno: 171: Required Authentication Context Reference values could not be satisfied
  • code: 404, errno: 176: Unknown subscription
  • code: 400, errno: 177: Unknown subscription plan
  • code: 400, errno: 178: Subscription payment token rejected
  • code: 503, errno: 201: Service unavailable
  • code: 503, errno: 202: Feature not enabled
  • code: 500, errno: 203: A backend service request failed.
  • code: 500, errno: 998: An internal validation check failed.

The following errors include additional response properties:

  • errno: 100: level, levelRequired
  • errno: 101: email
  • errno: 102: email
  • errno: 103: email
  • errno: 105
  • errno: 107: validation
  • errno: 108: param
  • errno: 111: serverTime
  • errno: 114: retryAfter, retryAfterLocalized, verificationMethod, verificationReason
  • errno: 120: email
  • errno: 124: deviceId
  • errno: 125: verificationMethod, verificationReason
  • errno: 126: email
  • errno: 130: region
  • errno: 132: reason, reasonCode
  • errno: 133: bouncedAt
  • errno: 134: bouncedAt
  • errno: 135: bouncedAt
  • errno: 152
  • errno: 153
  • errno: 162: clientId
  • errno: 164: authAt
  • errno: 167: redirectUri
  • errno: 169: invalidScopes
  • errno: 171: foundValue
  • errno: 201: retryAfter
  • errno: 202: retryAfter
  • errno: 203: service, operation
  • errno: 998: op, data

Responses from intermediary servers

As with any HTTP-based API, clients must handle standard errors that may be returned by proxies, load-balancers or other intermediary servers. These non-application responses can be identified by the absence of a correctly-formatted JSON response body.

Common examples include:

  • 413 Request Entity Too Large: may be returned by an upstream proxy server.
  • 502 Gateway Timeout: may be returned if a load-balancer can't connect to application servers.

Validation

In the documentation that follows, some properties of requests and responses are validated by common code that has been refactored and extracted. For reference, those common validations are defined here.

lib/routes/validators

  • HEX_STRING: /^(?:[a-fA-F0-9]{2})+$/
  • BASE_36: /^[a-zA-Z0-9]*$/
  • URL_SAFE_BASE_64: /^[A-Za-z0-9_-]+$/
  • PKCE_CODE_VERIFIER: /^[A-Za-z0-9-\._~]{43,128}$/
  • DISPLAY_SAFE_UNICODE: /^(?:[^\u0000-\u001F\u007F\u0080-\u009F\u2028-\u2029\uD800-\uDFFF\uE000-\uF8FF\uFFF9-\uFFFF])*$/
  • DISPLAY_SAFE_UNICODE_WITH_NON_BMP: /^(?:[^\u0000-\u001F\u007F\u0080-\u009F\u2028-\u2029\uE000-\uF8FF\uFFF9-\uFFFF])*$/
  • BEARER_AUTH_REGEX: /^Bearer\s+([a-z0-9+\/]+)$/i
  • service: string, max(16), regex(/^[a-zA-Z0-9\-]*$/)
  • hexString: string, regex(/^(?:[a-fA-F0-9]{2})+$/)
  • clientId: module.exports.hexString.length(16)
  • clientSecret: module.exports.hexString
  • accessToken: module.exports.hexString.length(64)
  • refreshToken: module.exports.hexString.length(64)
  • authorizationCode: module.exports.hexString.length(64)
  • scope: string, max(256), regex(/^[a-zA-Z0-9 _\/.:-]*$/), allow('')
  • assertion: string, min(50), max(10240), regex(/^[a-zA-Z0-9_\-\.~=]+$/)
  • pkceCodeChallengeMethod: string, valid('S256')
  • pkceCodeChallenge: string, length(43), regex(module, exports.URL_SAFE_BASE_64)
  • pkceCodeVerifier: string, length(43), regex(module, exports.PKCE_CODE_VERIFIER)
  • jwe: string, max(1024), regex(/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$/)
  • verificationMethod: string, valid()
  • authPW: string, length(64), regex(HEX_STRING), required
  • wrapKb: string, length(64), regex(/^(?:[a-fA-F0-9]{2})+$/)
  • recoveryKeyId: string, regex(HEX_STRING), max(32)
  • recoveryData: string, regex(/[a-zA-Z0-9.]/), max(1024), required
  • E164_NUMBER: /^\+[1-9]\d{1,14}$/
  • DIGITS: /^[0-9]+$/
  • DEVICE_COMMAND_NAME: /^[a-zA-Z0-9._\/\-:]{1,100}$/
  • IP_ADDRESS: string, ip

lib/metrics/context

  • SCHEMA: object({
    • deviceId: string, length(32), regex(HEX_STRING), optional
    • entrypoint: ENTRYPOINT_SCHEMA.optional
    • entrypointExperiment: ENTRYPOINT_SCHEMA.optional
    • entrypointVariation: ENTRYPOINT_SCHEMA.optional
    • flowId: string, length(64), regex(HEX_STRING), optional
    • flowBeginTime: number, integer, positive, optional
    • utmCampaign: UTM_CAMPAIGN_SCHEMA.optional
    • utmContent: UTM_SCHEMA.optional
    • utmMedium: UTM_SCHEMA.optional
    • utmSource: UTM_SCHEMA.optional
    • utmTerm: UTM_SCHEMA.optional }), unknown(false), and('flowId', 'flowBeginTime')
  • schema: SCHEMA.optional
  • requiredSchema: SCHEMA.required

lib/features

  • schema: array, items(string), optional

lib/devices

  • schema: {

    • id: isA.string.length(32).regex(HEX_STRING)
    • location: isA.object({
      • city: isA.string.optional.allow(null)
      • country: isA.string.optional.allow(null)
      • state: isA.string.optional.allow(null)
      • stateCode: isA.string.optional.allow(null)
      • })
    • name: isA.string.max(255).regex(DISPLAY_SAFE_UNICODE_WITH_NON_BMP)
    • nameResponse: isA.string.max(255).allow('')
    • type: isA.string.max(16)
    • pushCallback: validators.pushCallbackUrl({ scheme: 'https' }).regex(PUSH_SERVER_REGEX).max(255).allow('')
    • pushPublicKey: isA.string.max(88).regex(URL_SAFE_BASE_64).allow('')
    • pushAuthKey: isA.string.max(24).regex(URL_SAFE_BASE_64).allow('')
    • pushEndpointExpired: isA.boolean.strict
    • availableCommands: isA.object.pattern(validators.DEVICE_COMMAND_NAME
    • `isA.string.max(2048))

    }

API endpoints

Account

POST /account/create

Creates a user account. The client provides the email address with which this account will be associated and a stretched password. Stretching is detailed on the onepw wiki page.

This endpoint may send a verification email to the user. Callers may optionally provide the service parameter to indicate which service they are acting on behalf of. This is an opaque alphanumeric token that will be embedded in the verification link as a query parameter.

Creating an account also logs in. The response contains a sessionToken and, optionally, a keyFetchToken if the url has a query parameter of keys=true.

Query parameters
  • keys: boolean, optional

    Indicates whether a key-fetch token should be returned in the success response.

  • service: validators.service

    Opaque alphanumeric token to be included in verification links.

Request body
  • email: validators.email.required

    The primary email for this account.

  • authPW: validators.authPW

    The PBKDF2/HKDF-stretched password as a hex string.

  • preVerified: boolean

  • service: validators.service

    Opaque alphanumeric token to be included in verification links.

  • redirectTo: validators.redirectTo(config.smtp.redirectDomain).optional

    URL that the client should be redirected to after handling the request.

  • resume: string, max(2048), optional

    Opaque URL-encoded string to be included in the verification link as a query parameter.

  • metricsContext: metricsContext.schema

Response body
  • uid: string, regex(HEX_STRING), required

  • sessionToken: string, regex(HEX_STRING), required

  • keyFetchToken: string, regex(HEX_STRING), optional

  • authAt: number, integer

    Authentication time for the session (seconds since epoch).

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 101: Account already exists

  • code: 400, errno: 144: Email already exists

POST /account/login

Obtain a sessionToken and, optionally, a keyFetchToken if keys=true.

Query parameters
  • keys: boolean, optional

    Indicates whether a key-fetch token should be returned in the success response.

  • service: validators.service

    Opaque alphanumeric token to be included in verification links.

  • verificationMethod: validators.verificationMethod.optional

    If this param is specified, it forces the login to be verified using the specified method.

    Currently supported methods:

    • email
      • Sends an email with a confirmation link.
    • email-2fa
      • Sends an email with a confirmation code.
    • email-captcha
      • Sends an email with an unblock code.
Request body
  • email: validators.email.required

    The primary email for this account.

  • authPW: validators.authPW

    The PBKDF2/HKDF stretched password as a hex string.

  • service: validators.service

    Opaque alphanumeric token to be included in verification links.

  • redirectTo: validators.redirectTo(config.smtp.redirectDomain).optional

  • resume: string, optional

    Opaque URL-encoded string to be included in the verification link as a query parameter.

  • reason: string, max(16), optional

    Alphanumeric string indicating the reason for establishing a new session; may be "login" (the default) or "reconnect".

  • unblockCode: signinUtils.validators.UNBLOCK_CODE

    Alphanumeric code used to unblock certain rate-limitings.

  • metricsContext: metricsContext.schema

  • originalLoginEmail: validators.email.optional

    This parameter is the original email used to login with. Typically, it is specified after a user logins with a different email case, or changed their primary email address.

  • verificationMethod: validators.verificationMethod.optional

    If this param is specified, it forces the login to be verified using the specified method.

    Currently supported methods:

    • email
      • Sends an email with a confirmation link.
    • email-2fa
      • Sends an email with a confirmation code.
    • email-captcha
      • Sends an email with an unblock code.
Response body
  • uid: string, regex(HEX_STRING), required

  • sessionToken: string, regex(HEX_STRING), required

  • keyFetchToken: string, regex(HEX_STRING), optional

  • verificationMethod: string, optional

    The medium for how the user can verify.

  • verificationReason: string, optional

    The authentication method that required additional verification.

  • verified: boolean, required

  • authAt: number, integer

    Authentication time for the session (seconds since epoch).

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 102: Unknown account

  • code: 400, errno: 103: Incorrect password

  • code: 400, errno: 125: The request was blocked for security reasons

  • code: 400, errno: 127: Invalid unblock code

  • code: 400, errno: 142: Sign in with this email type is not currently supported

  • code: 400, errno: 149: This email can not currently be used to login

  • code: 400, errno: 160: This request requires two step authentication enabled on your account.

  • code: 422, errno: 151: Failed to send email

GET /account/status

πŸ”’πŸ”“ Optionally HAWK-authenticated with session token

Gets the status of an account.

Query parameters
  • uid: string, min(32), max(32), regex(validators.HEX_STRING)

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 108: Missing parameter in request body

POST /account/status

Gets the status of an account without exposing user data through query params. This endpoint is rate limited by fxa-customs-server.

Request body
  • email: validators.email.required

Response body
  • exists: boolean, required

GET /account/profile

πŸ”’ authenticated with OAuth bearer token or HAWK-authenticated with session token

Get the email and locale of a user.

If an OAuth bearer token is used, the values returned depend on the scopes that the token is authorized for:

  • email requires profile:email scope.

  • locale requires profile:locale scope.

  • authenticationMethods and authenticatorAssuranceLevel require profile:amr scope.

The profile scope includes all the above sub-scopes.

Response body
  • email: string, optional

  • locale: string, optional, allow(null)

  • authenticationMethods: array, items(string, required), optional

  • authenticatorAssuranceLevel: number, min(0)

  • profileChangedAt: number, min(0)

GET /account/keys

πŸ”’ HAWK-authenticated with key fetch token

Get the base-16 bundle of encrypted kA|wrapKb. The return value must be decrypted with a key derived from keyFetchToken, then wrapKb must be further decrypted with a key derived from the user's password.

Since keyFetchToken is single-use, this can only be done once per session. Note that keyFetchToken is consumed regardless of whether the request succeeds or fails.

This request will fail unless the account's email address and current session has been verified.

Response body
  • bundle: string, regex(validators.HEX_STRING)

    See decrypting the bundle for information on how to extract kA|wrapKb from the bundle.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 104: Unverified account

POST /account/unlock/resend_code

This endpoint is deprecated.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 410, errno: 116: This endpoint is no longer supported

POST /account/unlock/verify_code

This endpoint is deprecated.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 410, errno: 116: This endpoint is no longer supported

POST /account/reset

πŸ”’ HAWK-authenticated with account reset token

This sets the account password and resets wrapKb to a new random value.

Account reset tokens are single-use and consumed regardless of whether the request succeeds or fails. They are returned by the POST /password/forgot/verify_code endpoint.

The caller can optionally request a new sessionToken and keyFetchToken.

Query parameters
  • keys: boolean, optional

    Indicates whether a new keyFetchToken is required, default to false.

Request body
  • authPW: validators.authPW

    The PBKDF2/HKDF-stretched password as a hex string.

  • wrapKb: validators.wrapKb.optional

  • recoveryKeyId: validators.recoveryKeyId.optional

  • sessionToken: boolean, optional

    Indicates whether a new sessionToken is required, default to false.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 108: Missing parameter in request body

POST /account/destroy

πŸ”’πŸ”“ Optionally HAWK-authenticated with session token

Deletes an account. All stored data is erased. The client should seek user confirmation first. The client should erase data stored on any attached services before deleting the user's account data.

Request body
  • email: validators.email.required

    Primary email address of the account.

  • authPW: validators.authPW

    The PBKDF2/HKDF-stretched password as a hex string.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 103: Incorrect password

  • code: 400, errno: 138: Unverified session

PUT /account/ecosystemAnonId

πŸ”’ Authenticated with OAuth bearer token or HAWK-authenticated with session token

Adds new or updates existing user Ecosystem Anonymous ID.

Note that either request header If-Match or If-None-Match is required to perform this request.

  • If-Match with a value of your known Ecosystem Anonymous ID, SHA-256 hashed, to set a new ID if it matches the passed in ID.
  • If-None-Match with a value of * to set a new ID if one does not already exist, or your known Ecosystem Anonymous ID, SHA-256 hashed, to set a new ID if it does not match the passed in ID.
Request body
  • anonId: string, required

    The new Ecosystem Anonymous ID.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 163: Token does not contain the correct scope.
  • code: 412, errno: 190: Could not update because criteria set by a header, either If-None-Match or If-Match, was not met
  • code: 400, errno: 191: Header If-None-Match or If-Match is required to perform the request

Devices and sessions

POST /account/device

πŸ”’ HAWK-authenticated with session token or authenticated with OAuth refresh token

Creates or updates the device registration record associated with the auth token used for this request. At least one of name, type, pushCallback or the tuple { pushCallback, pushPublicKey, pushAuthKey } must be present. Beware that if you provide pushCallback without the pair { pushPublicKey, pushAuthKey }, both of those keys will be reset to the empty string.

pushEndpointExpired will be reset to false on update if the tuple { pushCallback, pushPublicKey, pushAuthKey } is specified.

Devices should register with this endpoint before attempting to access the user's sync data, so that an appropriate device name can be made available to other connected devices.

Request body
  • id: DEVICES_SCHEMA.id.optional

  • name: DEVICES_SCHEMA.name.optional

  • type: DEVICES_SCHEMA.type.optional

  • pushCallback: DEVICES_SCHEMA.pushCallback.optional

  • pushPublicKey: DEVICES_SCHEMA.pushPublicKey.optional

  • pushAuthKey: DEVICES_SCHEMA.pushAuthKey.optional

  • availableCommands: DEVICES_SCHEMA.availableCommands.optional

  • capabilities: array, length(0), optional

Response body
  • id: DEVICES_SCHEMA.id.required

  • createdAt: number, positive, optional

  • name: DEVICES_SCHEMA.nameResponse.optional

  • type: DEVICES_SCHEMA.type.optional

  • pushCallback: DEVICES_SCHEMA.pushCallback.optional

  • pushPublicKey: DEVICES_SCHEMA.pushPublicKey.optional

  • pushAuthKey: DEVICES_SCHEMA.pushAuthKey.optional

  • pushEndpointExpired: DEVICES_SCHEMA.pushEndpointExpired.optional

  • availableCommands: DEVICES_SCHEMA.availableCommands.optional

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 107: Invalid parameter in request body

  • code: 503, errno: 202: Feature not enabled

GET /account/device/commands

πŸ”’ HAWK-authenticated with session token or authenticated with OAuth refresh token

Fetches commands enqueued for the current device by prior calls to /account/devices/invoke_command. The device can page through the enqueued commands by using the index and limit parameters.

For more details, see the device registration docs.

Query parameters
  • index: number, optional

    The index of the most recently seen command item. Only commands enqueued after the given index will be returned.

  • limit: number, optional, min(0), max(100), default(100)

    The maximum number of commands to return. The default and maximum value for limit is 100.

Response body
  • index: number, required

    The largest index of the commands returned in this response. This value can be passed as the index parameter in subsequent calls in order to page through all the items.

  • last: boolean, optional

    Indicates whether more commands and enqueued than could be returned within the specific limit.

  • messages: array, items(object({ index: number, required, data: object({ command: string, max(255), required, payload: object, required, sender: DEVICES_SCHEMA.id, optional }), required })), optional

    An array of individual commands for the device to process.

POST /account/devices/invoke_command

πŸ”’ HAWK-authenticated with session token or authenticated with OAuth refresh token

Enqueues a command to be invoked on a target device.

For more details, see the device registration docs.

Request body
  • target: DEVICES_SCHEMA.id.required

    The id of the device on which to invoke the command.

  • command: string, required

    The id of the command to be invoked, as found in the device's availableCommands set.

  • payload: object, required

    Opaque payload to be forwarded to the device.

  • ttl: number, integer, min(0), max(10000000), optional

    The time in milliseconds after which the command should expire, if not processed by the device.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 157: Unavailable device command.

POST /account/devices/notify

πŸ”’ HAWK-authenticated with session token or authenticated with OAuth refresh token

Notifies a set of devices associated with the user's account of an event by sending a browser push notification. A typical use case would be to send a notification to another device after sending a tab with Sync, so it can sync too and display the tab in a timely manner.

Request body
  • to: string, valid('all'), required;
    or array, items(string, length(32), regex(HEX_STRING)), required

    Devices to notify. May be the string 'all' or an array containing the relevant device ids.

  • _endpointAction: string, valid('accountVerify'), optional

  • excluded: array, items(string, length(32), regex(HEX_STRING)), optional

    Array of device ids to exclude from the notification. Ignored unless to:"all" is specified.

  • payload: object, when('_endpointAction', { is: 'accountVerify', then: required, otherwise: required })

    Push payload, validated against pushpayloads.schema.json.

  • TTL: number, integer, min(0), optional

    Push notification TTL, defaults to 0.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 107: Invalid parameter in request body

  • code: 503, errno: 202: Feature not enabled

GET /account/attached_clients

πŸ”’ HAWK-authenticated with session token

Returns an array listing all the clients connected to the authenticated user's account, including devices, OAuth clients, and web sessions.

This endpoint is primarily designed to power the "devices and apps" view on the user's account settings page. Depending on the type of client, it will have at least one and possibly several of the following properties:

  • clientId: The OAuth client_id of the connected application.
  • sessionTokenId: The id of the sessionToken held by that client, if any.
  • refreshTokenId: The id of the OAuth refreshToken held by that client, if any.
  • deviceId: The id of the client's device record, if it has registered one.

These identifiers can be passed to /account/attached_client/destroy in order to disconnect the client.

Response body
  • clientId: string, regex(HEX_STRING), optional
  • sessionTokenId: string, regex(HEX_STRING), optional
  • refreshTokenId: string, regex(HEX_STRING), optional
  • deviceId: string, regex(HEX_STRING), optional
  • deviceType: DEVICES_SCHEMA.type.allow(null).required
  • isCurrentSession: boolean, required
  • name: DEVICES_SCHEMA.nameResponse.allow('').allow(null).required
  • createdTime: number, min(0), required, allow(null)
  • createdTimeFormatted: string, optional, allow('')
  • lastAccessTime: number, min(0), required, allow(null)
  • lastAccessTimeFormatted: string, optional, allow('')
  • approximateLastAccessTime: number, min(earliestSaneTimestamp), optional
  • approximateLastAccessTimeFormatted: string, optional, allow('')
  • scope: array(string), required, allow(null)
  • location: DEVICES_SCHEMA.location, optional Object containing the client's last-known geolocation info (state and country) if available.
  • userAgent: string, max(255), required, allow('')
  • os: string, max(255), allow(''), allow(null)

POST /account/attached_client/destroy

πŸ”’ HAWK-authenticated with session token

Destroy all tokens held by a connected client, disconnecting it from the user's account.

This endpoint is designed to be used in conjunction with /account/attached_clients. It accepts as the request body an object in the same format as returned by that endpoing, and will disconnect that client from the user's account.

Request body
  • clientId: string, regex(HEX_STRING), optional
  • sessionTokenId: string, regex(HEX_STRING), optional
  • refreshTokenId: string, regex(HEX_STRING), optional
  • deviceId: string, regex(HEX_STRING), optional

GET /account/devices

πŸ”’ HAWK-authenticated with session token or authenticated with OAuth refresh token

Returns an array of registered device objects for the authenticated user.

Response body
  • id: DEVICES_SCHEMA.id.required

  • isCurrentDevice: boolean, required

  • lastAccessTime: number, min(0), required, allow(null)

  • lastAccessTimeFormatted: string, optional, allow('')

  • approximateLastAccessTime: number, min(earliestSaneTimestamp), optional

  • approximateLastAccessTimeFormatted: string, optional, allow('')

  • location: DEVICES_SCHEMA.location

  • name: DEVICES_SCHEMA.nameResponse.allow('').required

  • type: DEVICES_SCHEMA.type.required

  • pushCallback: DEVICES_SCHEMA.pushCallback.allow(null).optional

  • pushPublicKey: DEVICES_SCHEMA.pushPublicKey.allow(null).optional

  • pushAuthKey: DEVICES_SCHEMA.pushAuthKey.allow(null).optional

  • pushEndpointExpired: DEVICES_SCHEMA.pushEndpointExpired.optional

  • availableCommands: DEVICES_SCHEMA.availableCommands.optional

GET /account/sessions

DEPRECATED: Please use /account/attached_clients instead.

πŸ”’ HAWK-authenticated with session token

Returns an array of session objects for the authenticated user.

Response body
  • id: string, regex(HEX_STRING), required

  • lastAccessTime: number, min(0), required, allow(null)

  • lastAccessTimeFormatted: string, optional, allow('')

  • approximateLastAccessTime: number, min(earliestSaneTimestamp), optional

  • approximateLastAccessTimeFormatted: string, optional, allow('')

  • createdTime: number, min(0), required, allow(null)

  • createdTimeFormatted: string, optional, allow('')

  • location: DEVICES_SCHEMA.location

    Object containing the client's state and country

  • userAgent: string, max(255), required, allow('')

  • os: string, max(255), allow(''), allow(null)

  • deviceId: DEVICES_SCHEMA.id.allow(null).required

  • deviceName: DEVICES_SCHEMA.nameResponse.allow('').allow(null).required

  • deviceAvailableCommands: DEVICES_SCHEMA.availableCommands.allow(null).required

  • deviceType: DEVICES_SCHEMA.type.allow(null).required

  • deviceCallbackURL: DEVICES_SCHEMA.pushCallback.allow(null).required

  • deviceCallbackPublicKey: DEVICES_SCHEMA.pushPublicKey.allow(null).required

  • deviceCallbackAuthKey: DEVICES_SCHEMA.pushAuthKey.allow(null).required

  • deviceCallbackIsExpired: DEVICES_SCHEMA.pushEndpointExpired.allow(null).required

  • isDevice: boolean, required

  • isCurrentDevice: boolean, required

POST /account/device/destroy

πŸ”’ HAWK-authenticated with session token or authenticated with OAuth refresh token

Destroys a device record and the associated sessionToken for the authenticated user. The identified device must sign in again to use the API after this request has succeeded.

Request body
  • id: DEVICES_SCHEMA.id.required

Emails

GET /recovery_email/status

πŸ”’ HAWK-authenticated with session token

Returns the "verified" status for the account's recovery email address.

Currently, each account is associated with exactly one email address. This address must be verified before the account can be used (specifically, POST /certificate/sign and GET /account/keys will return errors until the address is verified). In the future, this may be expanded to include multiple addresses, and/or alternate types of recovery methods (e.g. SMS). A new API will be provided for this extra functionality.

This call is used to determine the current state (verified or unverified) of the account. During account creation, until the address is verified, the agent can poll this method to discover when it should proceed with POST /certificate/sign and GET /account/keys.

Query parameters
  • reason: string, max(16), optional

Response body
  • email: string, required

  • verified: boolean, required

  • sessionVerified: boolean, optional

  • emailVerified: boolean, optional

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 401, errno: 110: Invalid authentication token in request signature

POST /recovery_email/resend_code

πŸ”’ HAWK-authenticated with session token

Re-sends a verification code to the account's recovery email address. The code is first sent when the account is created, but if the user thinks the message was lost or accidentally deleted, they can request a new message to be sent via this endpoint. The new message will contain the same code as the original message. When this code is provided to /v1/recovery_email/verify_code, the email will be marked as "verified".

This endpoint may send a verification email to the user. Callers may optionally provide the service parameter to indicate what identity-attached service they're acting on behalf of. This is an opaque alphanumeric token that will be embedded in the verification link as a query parameter.

Query parameters
  • service: validators.service

    Opaque alphanumeric token to be included in verification links.

  • type: string, max(32), alphanum, allow(), optional

Request body
  • email: validators.email.optional

  • service: validators.service

    Opaque alphanumeric token to be included in verification links.

  • redirectTo: validators.redirectTo(config.smtp.redirectDomain).optional

  • resume: string, max(2048), optional

    Opaque URL-encoded string to be included in the verification link as a query parameter.

  • type: string, max(32), alphanum, allow(), optional

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 150: Can not resend email code to an email that does not belong to this account

POST /recovery_email/verify_code

Verify tokens and/or recovery emails for an account. If a valid token code is detected, the account email and tokens will be set to verified. If a valid email code is detected, the email will be marked as verified.

The verification code will be a random token, delivered in the fragment identifier of a URL sent to the user's email address. Navigating to the URL opens a page that extracts the code from the fragment identifier and performs a POST to /recovery_email/verify_code. The link can be clicked from any browser, not just the one being attached to the Firefox account.

Request body
  • uid: string, max(32), regex(HEX_STRING), required

  • code: string, min(32), max(32), regex(HEX_STRING), required

  • service: validators.service

    Opaque alphanumeric token to be included in verification links.

  • reminder: string, regex(/^(?:first|second)$/), optional

    Indicates that verification originates from a reminder email.

  • type: string, max(32), alphanum, optional

    The type of code being verified.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 105: Invalid verification code

GET /recovery_emails

πŸ”’ HAWK-authenticated with session token

Returns an array of objects containing details of the email addresses associated with the logged-in user. Currently, the primary email address is always the one from the accounts table.

Response body
  • verified: boolean, required

  • isPrimary: boolean, required

  • email: validators.email.required

POST /recovery_email

πŸ”’ HAWK-authenticated with session token

Add a secondary email address to the logged-in account. The created address will be unverified and will not replace the primary email address.

Request body
  • email: validators.email.required

    The email address to add to the account.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 104: Unverified account

  • code: 400, errno: 138: Unverified session

  • code: 400, errno: 139: Can not add secondary email that is same as your primary

  • code: 400, errno: 140: Email already exists

  • code: 400, errno: 141: Email already exists

POST /recovery_email/destroy

πŸ”’ HAWK-authenticated with session token

Delete an email address associated with the logged-in user.

Request body
  • email: validators.email.required

    The email address to delete.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 138: Unverified session

POST /recovery_email/set_primary

πŸ”’ HAWK-authenticated with session token

This endpoint changes a user's primary email address. This email address must belong to the user and be verified.

Request body
  • email: validators.email.required

    The new primary email address of the user.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 138: Unverified session

  • code: 400, errno: 147: Can not change primary email to an unverified email

  • code: 400, errno: 148: Can not change primary email to an email that does not belong to this account

POST /recovery_email/secondary/verify_code

πŸ”’ HAWK-authenticated with session token

This endpoint verifies a secondary email using a time based (otp) code.

Request body
  • email: validators.email.required

    The secondary email address to verify.

  • code: validators.code.required

    Time based code to verify secondary email.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 138: Unverified session

  • code: 400, errno: 105: Invalid verification code

POST /recovery_email/secondary/resend_code

πŸ”’ HAWK-authenticated with session token

This endpoint resend the otp verification to verify the secondary email.

Request body
  • email: validators.email.required

    The secondary email address to verify.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 138: Unverified session

  • code: 400, errno: 150: Can not resend code for email that does not belong to the account

Oauth

GET /oauth/client/{client_id}

Retrieve metadata about the specified OAuth client, such as its display-name and redirect URI.

POST /account/scoped-key-data

πŸ”’ HAWK-authenticated with session token

Query for the information required to derive scoped encryption keys requested by the specified OAuth client.

POST /oauth/authorization

πŸ”’ HAWK-authenticated with session token

Authorize a new OAuth client connection to the user's account, returning a short-lived authentication code that the client can exchange for access tokens at the OAuth token endpoint.

This route behaves like the (oauth-server /authorization endpoint)[../fxa-oauth-server/docs/api.md#post-v1authorization] except that it is authenticated directly with a sessionToken rather than with a BrowserID assertion.

Request body
  • client_id: validators.clientId.required The OAuth client identifier provided by the connecting client application.
  • state: string, max(256), required An opaque string provided by the connecting client application, which will be returned unmodified alongside the authorization code. This can be used by the connecting client to guard against certain classes of attack in the redirect-based OAuth flow.
  • response_type: string, valid('code'), optional Determines the format of the response. Since we only support the authorization-code grant flow, the only permitted value is 'code'.
  • redirect_uri: string, URI, optional The URI at which the connecting client expects to receive the authorization code. If supplied this must match the value provided during OAuth client registration.
  • scope: string, optional A space-separated list of scope values that the connecting client will be granted. The requested scope will be provided by the connecting client as part of its authorization request, but may be pruned by the user in a confirmation dialog before being sent to this endpoint.
  • access_type: string, valid(online, offline), optional If specified, a value of offline will cause the connecting client to be granted a refresh token alongside its access token.
  • code_challenge_method: string, valid(S256), optional Required for public OAuth clients, who must authenticate their authorization code use via PKCE. The only support method is 'S256'.
  • code_challenge: string, length(43), regex(URL_SAFE_BASE_64), optional Required for public OAuth clients, who must authenticate their authorization code use via PKCE.
  • keys_jwe: string, validators.jwe, optional An encrypted bundle of key material, to be returned to the client when it redeems the authorization code.
  • acr_values: string, optional A space-separated list of ACR values specifying acceptable levels of user authentication. Specifying AAL2 will ensure that the user has been authenticated with 2FA before authorizing the requested grant.

POST /oauth/token

πŸ”’πŸ”“ Optionally HAWK-authenticated with session token

Grant new OAuth tokens for use by a connected client, using one of the following grant types:

  • grant_type=authorization_code: A single-use code obtained via OAuth redirect flow.
  • grant_type=refresh_token: A refresh token issued by a previous call to this endpoint.
  • grant_type=fxa-credentials: Directly grant tokens using an FxA sessionToken.

This is the "token endpoint" as defined in RFC6749, ande behaves like the (oauth-server /token endpoint)[../fxa-oauth-server/docs/api.md#post-v1token] except that the fxa-credentials grant can be authenticated directly with a sessionToken rather than with a BrowserID assertion.

Request body
  • client_id: validators.clientId, required The OAuth client identifier for the requesting client application.
  • client_secret: validators.hexString, optional The OAuth client secret for the requesting client application. Required for confidential clients, forbidden for public clients.
  • ppid_seed: integer.min(0).max(1024), optional Seed used in sub claim generation of JWT access tokens/ID tokens for clients with Pseudonymous Pairwise Identifiers (PPID) enabled. Used to forcibly rotate the sub claim. If not specified, it will default to 0.
  • resource: url, optional Indicates the target service or resource at which access is being requested. Its value must be an absolute URI, and may include a query component but must not include a fragment component. Added to the aud claim of JWT access tokens.
  • ttl: number.integer.min(0), optional The desired lifetime of the issued access token, in seconds. The actual lifetime may be smaller than requested depending on server configuration, and will be returned in the expired_in property of the response.
  • grant_type: string.allow('authorization_code', 'refresh_token', 'fxa-credentials'), optional The type of grant flow being used. If not specified, it will default to fxa-credentials unless a code parameter is provided, in which case it will default to authorization_code. The value of this parameter determines which other parameters will be expected in the request body, as follows:
    • When grant_type=authorization_code:
      • code: validators.authorizationCode, required The authorization code previously obtained through a redirect-based OAuth flow.
      • code_verifier: validators.pkceCodeVerifier, optional The PKCE code verifier used when obtaining code. This is required for public OAuth clients, who must authenticate their authorization code use via PKCE.
      • redirect_uri: string, URI, optional The URI at which the client received the authorization code. If supplied this must match the value provided during OAuth client registration.
    • When grant_type=refresh_token:
      • refresh_token: validators.refreshToken, required A refresh token, as issued by a previous call to this endpoint.
      • scope: string, optional A space-separated list of scope values that will be held by the generated token. These must be a subset of the scopes originally granted when the refresh token was generated.
    • When grant_type=fxa-credentials:
      • scope: string, optional A space-separated list of scope values that will be held by the generated tokens.
      • access_type: string, valid(online, offline), optional If specified, a value of offline will cause the client to be granted a refresh token alongside its access token.
      • In addition, the request must be authenticated with a sessionToken.
Response body
  • access_token: validators.accessToken, required An OAuth access token that the client can use to access data associated with the user's account.
  • refresh_token: validators.refreshToken, optional A token that can be used to grant a new access token when the current one expires, via grant_type=refresh_token on this endpoint.
  • id_token: validators.assertion, optional Open OpenID Connect identity token, provisioned if the openid scope was requested.
  • scope: string, required The scope values held by the granted access token.
  • auth_at: number, optional Where available, the timestamp at which the user last authenticated to FxA, in seconds since the epoch.
  • token_type: string.allow('bearer'), required The type of token, which determins how the client should use it in subsequent requests. Currently only Bearer tokens are supported.
  • expires_in: number.integer.min(0), required The number of seconds until the access token will expire.
Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 401, errno: 110: Invalid authentication token in request signature

  • code: 500, errno: 998: An internal validation check failed.

POST /oauth/destroy

Destroy an OAuth access token or refresh token.

This is the "token revocation endpoint" as defined in RFC7009 and should be used by clients to explicitly revoke any OAuth tokens that they are no longer using.

Request body
  • client_id: validators.clientId, required The OAuth client identifier for the requesting client application.
  • client_secret: validators.hexString, optional The OAuth client secret for the requesting client application. Required for confidential clients, forbidden for public clients.
  • token: validators.accessToken, required The token to be revoked. If the specific token does not exist then this call will silently succeed.
  • token_type_hint: string optional A hint as to what type of token is being revoked. Expected values are "access_token" or "refresh_token", Unrecognized values will be silently ignored, and specifying an incorrect hint may cause to the request to take longer but will still result in the token being destroyed.
Response body

No information is returned in the response body.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 500, errno: 162: Unknown client id.

  • code: 401, errno: 171: Incorrect client secret.

Password

POST /password/change/start

Begin the "change password" process. Returns a single-use passwordChangeToken, to be sent to POST /password/change/finish. Also returns a single-use keyFetchToken.

Request body
  • email: validators.email.required

    Primary email address of the account.

  • oldAuthPW: validators.authPW

    The PBKDF2/HKDF-stretched password as a hex string.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 103: Incorrect password

POST /password/change/finish

πŸ”’ HAWK-authenticated with password change token

Change the password and update wrapKb. Optionally returns sessionToken and keyFetchToken.

Query parameters
  • keys: boolean, optional

    Indicates whether a new keyFetchToken is required, default to false.

Request body
  • authPW: validators.authPW

    The PBKDF2/HKDF-stretched password as a hex string.

  • wrapKb: validators.wrapKb

    The new wrapKb value as a hex string.

  • sessionToken: string, min(64), max(64), regex(HEX_STRING), optional

    Indicates whether a new sessionToken is required, default to false.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 138: Unverified session

POST /password/forgot/send_code

Requests a "reset password" code to be sent to the user's recovery email. The user should type this code into the agent, which will then submit it to POST /password/forgot/verify_code.

The code will be either 8 or 16 digits long, with the length indicated in the response. The email will either contain the code itself or the URL for a web page that displays the code.

The response includes passwordForgotToken, which must be submitted with the code to POST /password/forgot/verify_code.

The response also specifies the TTL of passwordForgotToken and an upper limit on the number of times the token may be submitted. By limiting the number of submission attempts, we also limit an attacker's ability to guess the code. After the token expires, or the maximum number of submissions has been made, the agent must call this endpoint again to generate a new code and token pair.

Each account can have at most one passwordForgotToken valid at a time. Calling this endpoint causes existing tokens to be invalidated and a new one created. Each token is associated with a specific code, so by extension the codes are invalidated with their tokens.

Query parameters
  • service: validators.service

    Identifies the relying service the user was interacting with that triggered the password reset.

  • keys: boolean, optional

Request body
  • email: validators.email.required

    Recovery email for the account.

  • service: validators.service

    Identifies the relying service the user was interacting with that triggered the password reset.

  • redirectTo: validators.redirectTo(redirectDomain).optional

    URL that the client should be redirected to after handling the request.

  • resume: string, max(2048), optional

    Opaque URL-encoded string to be included in the verification link as a query parameter.

  • metricsContext: metricsContext.schema

Response body
  • passwordForgotToken: string

  • ttl: number

  • codeLength: number

  • tries: number

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 145: Reset password with this email type is not currently supported

POST /password/forgot/resend_code

πŸ”’ HAWK-authenticated with password forgot token

Resends the email from POST /password/forgot/send_code, for use when the original email has been lost or accidentally deleted.

This endpoint requires the passwordForgotToken returned in the original response, so only the original client which started the process may request a resent message. The response will match that from POST /password/forgot/send_code, except ttl will be lower to indicate the shorter validity period. tries will also be lower if POST /password/forgot/verify_code has been called.

Query parameters
  • service: validators.service

    Identifies the relying service the user was interacting with that triggered the password reset.

Request body
  • email: validators.email.required

    Recovery email for the account.

  • service: validators.service

    Identifies the relying service the user was interacting with that triggered the password reset.

  • redirectTo: validators.redirectTo(redirectDomain).optional

    URL that the client should be redirected to after handling the request.

  • resume: string, max(2048), optional

    Opaque URL-encoded string to be included in the verification link as a query parameter.

Response body
  • passwordForgotToken: string

  • ttl: number

  • codeLength: number

  • tries: number

POST /password/forgot/verify_code

πŸ”’ HAWK-authenticated with password forgot token

The code returned by POST /v1/password/forgot/send_code should be submitted to this endpoint with the passwordForgotToken. For successful requests, the server will return accountResetToken, to be submitted in requests to POST /account/reset to reset the account password and wrapKb.

Request body
  • code: string, min(32), max(32), regex(HEX_STRING), required

    The code sent to the user's recovery email.

  • accountResetWithRecoveryKey: boolean, optional

Response body
  • accountResetToken: string

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 105: Invalid verification code

GET /password/forgot/status

πŸ”’ HAWK-authenticated with password forgot token

Returns the status of a passwordForgotToken. Success responses indicate the token has not yet been consumed. For consumed or expired tokens, an HTTP 401 response with errno: 110 will be returned.

Response body
  • tries: number

  • ttl: number

Recovery codes

GET /recoveryCodes

πŸ”’ HAWK-authenticated with session token

Return new recovery codes while removing old ones.

Response body
  • recoveryCodes: array, items(string)

POST /session/verify/recoveryCode

πŸ”’ HAWK-authenticated with session token

Verify a session using a recovery code.

Request body
  • code: string, max(RECOVERY_CODE_SANE_MAX_LENGTH), regex(BASE_36), required

Response body
  • remaining: number

Recovery key

POST /recoveryKey

πŸ”’ HAWK-authenticated with session token

Creates a new recovery key for a user.

Recovery keys are one-time-use tokens that can be used to recover the user's kB if they forget their password. For more details, see the recovery keys docs.

Request body
  • recoveryKeyId: validators.recoveryKeyId

    A unique identifier for this recovery key, derived from the key via HKDF.

  • recoveryData: validators.recoveryData

    An encrypted bundle containing the user's kB.

GET /recoveryKey/{recoveryKeyId}

πŸ”’ HAWK-authenticated with account reset token

Retrieve the account recovery data associated with the given recovery key.

POST /recoveryKey/exists

πŸ”’πŸ”“ Optionally HAWK-authenticated with session token

This route checks to see if given user has setup an account recovery key. When used during the password reset flow, an email can be provided (instead of a sessionToken) to check for the status. However, when using an email, the request is rate limited.

Request body
  • email: validators.email.optional

Response body
  • exists: boolean, required

DELETE /recoveryKey

πŸ”’ HAWK-authenticated with session token

This route remove an account's recovery key. When the key is removed, it can no longer be used to restore an account's kB.

Security events

GET /securityEvents

πŸ”’ HAWK-authenticated with session token

Returns a list of all security events for a signed in account having account.create, account.login, account.reset events.

DELETE /securityEvents

πŸ”’ HAWK-authenticated with session token

Deletes all the security events of a signed in account.

Session

POST /session/destroy

πŸ”’ HAWK-authenticated with session token

Destroys the current session and invalidates sessionToken, to be called when a user signs out. To sign back in, a call must be made to POST /account/login to obtain a new sessionToken.

Request body
  • customSessionToken: string, min(64), max(64), regex(HEX_STRING), optional

    Custom session token id to destroy.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 401, errno: 110: Invalid authentication token in request signature

POST /session/reauth

πŸ”’ HAWK-authenticated with session token

Re-authenticate an existing session token. This is equivalent to calling /account/login, but it re-uses an existing session token rather than generating a new one, allowing the caller to maintain session state such as verification and device registration.

Query parameters
  • keys: boolean, optional

  • service: validators.service

  • verificationMethod: validators.verificationMethod.optional

Request body
  • email: validators.email.required

  • authPW: validators.authPW

  • service: validators.service

  • redirectTo: validators.redirectTo(config.smtp.redirectDomain).optional

  • resume: string, optional

  • reason: string, max(16), optional

  • unblockCode: signinUtils.validators.UNBLOCK_CODE

  • metricsContext: metricsContext.schema

  • originalLoginEmail: validators.email.optional

  • verificationMethod: validators.verificationMethod.optional

Response body
  • uid: string, regex(HEX_STRING), required

  • keyFetchToken: string, regex(HEX_STRING), optional

  • verificationMethod: string, optional

  • verificationReason: string, optional

  • verified: boolean, required

  • authAt: number, integer

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 102: Unknown account

  • code: 400, errno: 103: Incorrect password

  • code: 400, errno: 125: The request was blocked for security reasons

  • code: 400, errno: 127: Invalid unblock code

  • code: 400, errno: 142: Sign in with this email type is not currently supported

  • code: 400, errno: 149: This email can not currently be used to login

  • code: 400, errno: 160: This request requires two step authentication enabled on your account.

GET /session/status

πŸ”’ HAWK-authenticated with session token

Returns a success response if the session token is valid.

Response body
  • state: string, required

  • uid: string, regex(HEX_STRING), required

POST /session/duplicate

πŸ”’ HAWK-authenticated with session token

Create a new sessionToken that duplicates the current session. It will have the same verification status as the current session, but will have a distinct verification code.

Request body
  • reason: string, max(16), optional

Sign

POST /certificate/sign

πŸ”’ HAWK-authenticated with session token

Sign a BrowserID public key. The server is given a public key and returns a signed certificate using the same JWT-like mechanism as a BrowserID primary IdP would (see browserid-certifier for details). The signed certificate includes a principal.email property to indicate the Firefox Account identifier (a UUID at the account server's primary domain) and is stamped with an expiry time based on the duration parameter.

This request will fail unless the primary email address for the account has been verified.

Clients should include a query parameter, service, for metrics and validation purposes. The value of service should be sync when connecting to Firefox Sync or the OAuth client_id when connecting to an OAuth relier.

If you do not specify a service parameter, or if you specify service=sync, this endpoint assumes the request is from a legacy Sync client. If the session token doesn't have a corresponding device record, one will be created automatically by the server.

The signed certificate includes these additional claims:

  • fxa-generation: A number that increases each time the user's password is changed.

  • fxa-keysChangedAt: A timestamp that increases each time the user's encryption key is changed.

  • fxa-profileChangedAt: A timestamp that increases each time the user's core profile data is changed.

  • fxa-lastAuthAt: Authentication time for this session, in seconds since epoch.

  • fxa-verifiedEmail: The user's verified recovery email address.

  • fxa-tokenVerified: A boolean indicating whether the user's login was verified using an email confirmation or 2FA in addition to their password.

  • fxa-amr: A list of strings giving the ways in which the user was authenticated. Possible values include:

    • pwd: the user provided the account password
    • email: the user completed an email confirmation loop
    • otp: the user completed a 2FA challenge
  • fxa-aal: An integer giving the "authenticator assurance level" at which the user was authenticated - that is, the number of independent auth factors that they provided during login.

Query parameters
  • service: validators.service

Request body
  • publicKey: object({ algorithm: string, valid('RS', 'DS'), required, n: string, e: string, y: string, p: string, q: string, g: string, version: string }), required

    The key to sign (run bin/generate-keypair from browserid-crypto).

  • duration: number, integer, min(0), max(), required

    Time interval in milliseconds until the certificate will expire, up to a maximum of 24 hours.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 104: Unverified account

  • code: 400, errno: 108: Missing parameter in request body

  • code: 400, errno: 138: Unverified session

Signin codes

POST /signinCodes/consume

Exchange a single-use signin code for an email address.

Request body
  • code: string, regex(validators.URL_SAFE_BASE_64), required

    The signin code.

  • metricsContext: metricsContext.requiredSchema

    Metrics context data for the new flow.

Response body
  • email: validators.email.required

    The email address associated with the signin code.

Sms

POST /sms

πŸ”’ HAWK-authenticated with session token

Sends an SMS message.

Request body
  • phoneNumber: string, regex(validators.E164_NUMBER), required

    The phone number to send the message to, in E.164 format.

  • messageId: number, positive, required

    The id of the message to send.

  • metricsContext: metricsContext.schema

    Metrics context data for the request.

  • features: features.schema

    Enabled features for the request.

Error responses

Failing requests may be caused by the following errors (this is not an exhaustive list):

  • code: 400, errno: 129: Invalid phone number

  • code: 400, errno: 130: Invalid region

GET /sms/status

πŸ”’ HAWK-authenticated with session token

Returns SMS status for the current user.

Query parameters
  • country: string, regex(/^[A-Z][a-z]$/), optional

    Skip geo-lookup and act as if the user is in the specified country.

Subscriptions

GET /oauth/subscriptions/plans

πŸ”’ authenticated with OAuth bearer token Returns a list of available subscription plans.

GET /oauth/subscriptions/active

πŸ”’ authenticated with OAuth bearer token Returns a list of active subscriptions for the user.

POST /oauth/subscriptions/active

πŸ”’ authenticated with OAuth bearer token Subscribe the user to a plan using a payment token.

DELETE /oauth/subscriptions/active/{subscriptionId}

πŸ”’ authenticated with OAuth bearer token Cancel an active subscription for the user.

POST /oauth/subscriptions/updatePayment

πŸ”’ authenticated with OAuth bearer token Update the user's default payment method using a payment token.

GET /oauth/subscriptions/customer

πŸ”’ authenticated with OAuth bearer token Returns customer details, including limited payment information.

POST /oauth/subscriptions/customer

πŸ”’ authenticated with OAuth bearer token Create a new customer object for use with subscription payments.

POST /oauth/subscriptions/active/new

πŸ”’ authenticated with OAuth bearer token Subscribe the user to a price using a payment method id.

POST /oauth/subscriptions/invoice/retry

πŸ”’ authenticated with OAuth bearer token Retry an incomplete subscription invoice with a new payment method id.

POST /oauth/subscriptions/setupintent/create

πŸ”’ authenticated with OAuth bearer token Create a new setup intent for attaching a new payment method to the user.

POST /oauth/subscriptions/paymentmethod/default

πŸ”’ authenticated with OAuth bearer token Update a user's default payment method for invoices to the attached payment method id.

Totp

POST /totp/create

πŸ”’ HAWK-authenticated with session token

Create a new randomly generated TOTP token for a user if they do not currently have one.

Request body
  • metricsContext: metricsContext.schema

POST /totp/destroy

πŸ”’ HAWK-authenticated with session token

Deletes the current TOTP token for the user.

GET /totp/exists

πŸ”’ HAWK-authenticated with session token

Checks to see if the user has a TOTP token.

POST /session/verify/totp

πŸ”’ HAWK-authenticated with session token

Verifies the current session if the passed TOTP code is valid.

Request body
  • code: string, max(32), regex(validators.DIGITS), required

    The TOTP code to check

  • service: validators.service

Response body
  • success: boolean, required

  • recoveryCodes: array, items(string), optional

Unblock codes

POST /account/login/send_unblock_code

Send an unblock code via email to reset rate-limiting for an account.

Request body
  • email: validators.email.required

    Primary email for the account.

  • metricsContext: metricsContext.schema

POST /account/login/reject_unblock_code

Used to reject and report unblock codes that were not requested by the user.

Request body
  • uid: string, max(32), regex(HEX_STRING), required

    The user id.

  • unblockCode: string, regex(BASE_36), length(unblockCodeLen), required

    The unblock code.

Util

POST /get_random_bytes

Get 32 bytes of random data. This should be combined with locally-sourced entropy when creating salts, etc.

GET /verify_email

Query parameters
  • code: string, max(32), regex(HEX_STRING), required

  • uid: string, max(32), regex(HEX_STRING), required

  • service: string, max(16), alphanum, optional

  • redirectTo: validators.redirectTo(redirectDomain).optional

GET /complete_reset_password

Query parameters
  • email: validators.email.required

  • code: string, max(32), regex(HEX_STRING), required

  • token: string, max(64), regex(HEX_STRING), required

  • service: string, max(16), alphanum, optional

  • redirectTo: validators.redirectTo(redirectDomain).optional

Back-off protocol

During periods of heavy load, the server may request that clients enter a "back-off" state, in which they avoid making further requests.

At such times, it will return a 503 Service Unavailable response with a Retry-After header denoting the number of seconds to wait before issuing any further requests. It will also include errno: 201 and a retryAfter field matching the value of the Retry-After header in the body.

For example, the following response indicates that the client should suspend making further requests for 30 seconds:

HTTP/1.1 503 Service Unavailable
Retry-After: 30
Content-Type: application/json

{
  "code": 503,
  "errno": 201,
  "error": "Service Unavailable",
  "message": "Service unavailable",
  "info": "https://github.com/mozilla/fxa/blob/main/packages/fxa-auth-server/docs/api.md#response-format",
  "retryAfter": 30,
  "retryAfterLocalized": "in a few seconds"
}