92 KiB
Firefox Accounts authentication server API
This document is automatically generated. If you are editing it, read this section first.
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 mozilla/fxa-js-client
.
- Overview
- API endpoints
- Account
- POST /account/create
- POST /account/login
- GET /account/status (🔒🔓 sessionToken)
- POST /account/status
- GET /account/profile (🔒 sessionToken, oauthToken)
- GET /account/keys (🔒 keyFetchToken)
- POST /account/unlock/resend_code
- POST /account/unlock/verify_code
- POST /account/reset (🔒 accountResetToken)
- POST /account/destroy (🔒🔓 sessionToken)
- Devices and sessions
- POST /account/device (🔒 sessionToken)
- GET /account/device/commands (🔒 sessionToken)
- POST /account/devices/invoke_command (🔒 sessionToken)
- POST /account/devices/notify (🔒 sessionToken)
- GET /account/devices (🔒 sessionToken)
- GET /account/sessions (🔒 sessionToken)
- POST /account/device/destroy (🔒 sessionToken)
- Emails
- Password
- Recovery codes
- Recovery key
- Session
- Sign
- Signin codes
- Sms
- Token codes
- Totp
- Unblock codes
- Util
- Account
- Example flows
- Back-off protocol
- This document
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 Levelcode: 400, errno: 101
: Account already existscode: 400, errno: 102
: Unknown accountcode: 400, errno: 103
: Incorrect passwordcode: 400, errno: 104
: Unverified accountcode: 400, errno: 105
: Invalid verification codecode: 400, errno: 106
: Invalid JSON in request bodycode: 400, errno: 107
: Invalid parameter in request bodycode: 400, errno: 108
: Missing parameter in request bodycode: 401, errno: 109
: Invalid request signaturecode: 401, errno: 110
: Invalid authentication token in request signaturecode: 401, errno: 111
: Invalid timestamp in request signaturecode: 411, errno: 112
: Missing content-length headercode: 413, errno: 113
: Request body too largecode: 429, errno: 114
: Client has sent too many requestscode: 401, errno: 115
: Invalid nonce in request signaturecode: 410, errno: 116
: This endpoint is no longer supportedcode: 400, errno: 120
: Incorrect email casecode: 400, errno: 123
: Unknown devicecode: 400, errno: 124
: Session already registered by another devicecode: 400, errno: 125
: The request was blocked for security reasonscode: 400, errno: 126
: Account must be resetcode: 400, errno: 127
: Invalid unblock codecode: 400, errno: 129
: Invalid phone numbercode: 400, errno: 130
: Invalid regioncode: 400, errno: 131
: Invalid message idcode: 500, errno: 132
: Message rejectedcode: 400, errno: 133
: Email account sent complaintcode: 400, errno: 134
: Email account hard bouncedcode: 400, errno: 135
: Email account soft bouncedcode: 400, errno: 136
: Email already existscode: 400, errno: 137
: Can not delete primary emailcode: 400, errno: 138
: Unverified sessioncode: 400, errno: 139
: Can not add secondary email that is same as your primarycode: 400, errno: 140
: Email already existscode: 400, errno: 141
: Email already existscode: 400, errno: 142
: Sign in with this email type is not currently supportedcode: 400, errno: 143
: Unknown emailcode: 400, errno: 144
: Email already existscode: 400, errno: 145
: Reset password with this email type is not currently supportedcode: 400, errno: 146
: Invalid signin codecode: 400, errno: 147
: Can not change primary email to an unverified emailcode: 400, errno: 148
: Can not change primary email to an email that does not belong to this accountcode: 400, errno: 149
: This email can not currently be used to logincode: 400, errno: 150
: Can not resend email code to an email that does not belong to this accountcode: 400, errno: 151
: Failed to send emailcode: 400, errno: 152
: Invalid token verification codecode: 400, errno: 153
: Expired token verification codecode: 400, errno: 154
: A TOTP token already exists for this account.code: 400, errno: 155
: A 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: 503, errno: 201
: Service unavailablecode: 503, errno: 202
: Feature not enabledcode: 500, errno: 203
: A backend service request failed.code: 500, errno: 999
: Unspecified error
The following errors include additional response properties:
errno: 100
: level, levelRequirederrno: 101
: emailerrno: 102
: emailerrno: 103
: emailerrno: 105
errno: 107
: validationerrno: 108
: paramerrno: 111
: serverTimeerrno: 114
: retryAfter, retryAfterLocalized, verificationMethod, verificationReasonerrno: 120
: emailerrno: 124
: deviceIderrno: 125
: verificationMethod, verificationReasonerrno: 126
: emailerrno: 130
: regionerrno: 132
: reason, reasonCodeerrno: 133
: bouncedAterrno: 134
: bouncedAterrno: 135
: bouncedAterrno: 152
errno: 153
errno: 201
: retryAftererrno: 202
: retryAftererrno: 203
: service, operation
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_-]+$/
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])*$/
service
:string, max(16), regex(/^[a-zA-Z0-9\-]*$/g)
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), optionalflowId
: string, length(64), regex(HEX_STRING), optionalflowBeginTime
: number, integer, positive, optionalutmCampaign
: string, optionalutmContent
: string, optionalutmMedium
: string, optionalutmSource
: string, optionalutmTerm
: string, 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)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.strictavailableCommands
: 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, optionalIndicates whether a key-fetch token should be returned in the success response.
-
service
: validators.serviceOpaque alphanumeric token to be included in verification links.
Request body
-
email
: validators.email.requiredThe primary email for this account.
-
authPW
: validators.authPWThe PBKDF2/HKDF-stretched password as a hex string.
-
preVerified
: boolean -
service
: validators.serviceOpaque alphanumeric token to be included in verification links.
-
redirectTo
: validators.redirectTo(config.smtp.redirectDomain).optionalURL that the client should be redirected to after handling the request.
-
resume
: string, max(2048), optionalOpaque 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, integerAuthentication 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, optionalIndicates whether a key-fetch token should be returned in the success response.
-
service
: validators.serviceOpaque alphanumeric token to be included in verification links.
-
verificationMethod
: validators.verificationMethod.optionalIf 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.requiredThe primary email for this account.
-
authPW
: validators.authPWThe PBKDF2/HKDF stretched password as a hex string.
-
service
: validators.serviceOpaque alphanumeric token to be included in verification links.
-
redirectTo
: validators.redirectTo(config.smtp.redirectDomain).optional -
resume
: string, optionalOpaque URL-encoded string to be included in the verification link as a query parameter.
-
reason
: string, max(16), optionalAlphanumeric string indicating the reason for establishing a new session; may be "login" (the default) or "reconnect".
-
unblockCode
: signinUtils.validators.UNBLOCK_CODEAlphanumeric code used to unblock certain rate-limitings.
-
metricsContext
: metricsContext.schema -
originalLoginEmail
: validators.email.optionalThis 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.optionalIf 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, optionalThe medium for how the user can verify.
-
verificationReason
: string, optionalThe authentication method that required additional verification.
-
verified
: boolean, required -
authAt
: number, integerAuthentication 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.
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
requiresprofile:email
scope. -
locale
requiresprofile:locale
scope. -
authenticationMethods
andauthenticatorAssuranceLevel
requireprofile: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)
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, optionalIndicates whether a new
keyFetchToken
is required, default tofalse
.
Request body
-
authPW
: validators.authPWThe PBKDF2/HKDF-stretched password as a hex string.
-
wrapKb
: validators.wrapKb.optional -
recoveryKeyId
: validators.recoveryKeyId.optional -
sessionToken
: boolean, optionalIndicates whether a new
sessionToken
is required, default tofalse
. -
metricsContext
: metricsContext.schema
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.requiredPrimary email address of the account.
-
authPW
: validators.authPWThe 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
Devices and sessions
POST /account/device
🔒 HAWK-authenticated with session token
Either:
-
Registers a new device for this session if no device id is specified, or;
-
Updates existing device details for this session if a device id is specified.
If no device id is specified,
both name
and type
must be provided.
If a device id is specified,
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 obtain a signed certificate and perform their first sync, so that an appropriate device name can be made available to other connected devices.
Request body
-
id
: DEVICES_SCHEMA.id.required -
name
: DEVICES_SCHEMA.name.optional;
or DEVICES_SCHEMA.name.required -
type
: DEVICES_SCHEMA.type.optional;
or DEVICES_SCHEMA.type.required -
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
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, optionalThe 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, requiredThe 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, optionalIndicates 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 })), optionalAn array of individual commands for the device to process.
POST /account/devices/invoke_command
🔒 HAWK-authenticated with session 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.requiredThe id of the device on which to invoke the command.
-
command
: string, requiredThe id of the command to be invoked, as found in the device's
availableCommands
set. -
payload
: object, requiredOpaque payload to be forwarded to the device.
-
ttl
: number, integer, min(0), max(10000000), optionalThe 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
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)), requiredDevices 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)), optionalArray 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), optionalPush 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/devices
🔒 HAWK-authenticated with session 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
🔒 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.locationObject 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
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.serviceOpaque alphanumeric token to be included in verification links.
-
type
: string, max(32), alphanum, allow(), optional
Request body
-
email
: validators.email.optional -
service
: validators.serviceOpaque alphanumeric token to be included in verification links.
-
redirectTo
: validators.redirectTo(config.smtp.redirectDomain).optional -
resume
: string, max(2048), optionalOpaque URL-encoded string to be included in the verification link as a query parameter.
-
metricsContext
: metricsContext.schema -
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.
Query parameters
-
service
: validators.serviceOpaque alphanumeric token to be included in verification links.
-
reminder
: string, max(32), alphanum, optionalDeprecated.
-
type
: string, max(32), alphanum, optionalThe type of code being verified.
Request body
-
uid
: string, max(32), regex(HEX_STRING), required -
code
: string, min(32), max(32), regex(HEX_STRING), required -
service
: validators.serviceOpaque alphanumeric token to be included in verification links.
-
reminder
: string, max(32), alphanum, optionalDeprecated.
-
type
: string, max(32), alphanum, optionalThe type of code being verified.
-
marketingOptIn
: booleanSet to true if the user has opted-in to our marketing. When verified, the auth-server will notify Basket.
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.requiredThe 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 -
code: 400, errno: 151
: Failed to send email
POST /recovery_email/destroy
🔒 HAWK-authenticated with session token
Delete an email address associated with the logged-in user.
Request body
-
email
: validators.email.requiredThe 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.requiredThe 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
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.requiredPrimary email address of the account.
-
oldAuthPW
: validators.authPWThe 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, optionalIndicates whether a new
keyFetchToken
is required, default tofalse
.
Request body
-
authPW
: validators.authPWThe PBKDF2/HKDF-stretched password as a hex string.
-
wrapKb
: validators.wrapKbThe new
wrapKb
value as a hex string. -
sessionToken
: string, min(64), max(64), regex(HEX_STRING), optionalIndicates whether a new
sessionToken
is required, default tofalse
.
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.serviceIdentifies the relying service the user was interacting with that triggered the password reset.
-
keys
: boolean, optional
Request body
-
email
: validators.email.requiredRecovery email for the account.
-
service
: validators.serviceIdentifies the relying service the user was interacting with that triggered the password reset.
-
redirectTo
: validators.redirectTo(redirectDomain).optionalURL that the client should be redirected to after handling the request.
-
resume
: string, max(2048), optionalOpaque 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.serviceIdentifies the relying service the user was interacting with that triggered the password reset.
Request body
-
email
: validators.email.requiredRecovery email for the account.
-
service
: validators.serviceIdentifies the relying service the user was interacting with that triggered the password reset.
-
redirectTo
: validators.redirectTo(redirectDomain).optionalURL that the client should be redirected to after handling the request.
-
resume
: string, max(2048), optionalOpaque 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
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), requiredThe code sent to the user's recovery email.
-
metricsContext
: metricsContext.schema -
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 -
metricsContext
: metricsContext.schema
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.recoveryKeyIdA unique identifier for this recovery key, derived from the key via HKDF.
-
recoveryData
: validators.recoveryDataAn 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.
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), optionalCustom 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-lastAuthAt
: Authentication time for this session, in seconds since epoch. -
fxa-verifiedEmail
: The user's verified recovery email address.
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 }), requiredThe key to sign (run
bin/generate-keypair
from browserid-crypto). -
duration
: number, integer, min(0), max(), requiredTime 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), requiredThe signin code.
-
metricsContext
: metricsContext.requiredSchemaMetrics context data for the new flow.
Response body
-
email
: validators.email.requiredThe 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), requiredThe phone number to send the message to, in E.164 format.
-
messageId
: number, positive, requiredThe id of the message to send.
-
metricsContext
: metricsContext.schemaMetrics context data for the request.
-
features
: features.schemaEnabled 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]$/), optionalSkip geo-lookup and act as if the user is in the specified country.
Token codes
POST /session/verify/token
🔒 HAWK-authenticated with session token
Verify a session using a token code.
Request body
-
code
: string, min(TOKEN_CODE_LENGTH), max(TOKEN_CODE_LENGTH), regex(DIGITS), requiredThe code
-
uid
: string, max(32), regex(HEX_STRING), optionalThe uid associated with the token code
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), requiredThe TOTP code to check
-
metricsContext
: metricsContext.schema -
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.requiredPrimary 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), requiredThe user id.
-
unblockCode
: string, regex(BASE_36), length(unblockCodeLen), requiredThe 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-auth-server/blob/master/docs/api.md#response-format",
"retryAfter": 30,
"retryAfterLocalized": "in a few seconds"
}
This document
This document is automatically generated by a script that parses the source code and the document itself.
All changes to this document will be lost unless they are made inside delimiting HTML comments of the form:
<!--begin-foo-bar-->
YOUR CHANGE GOES HERE
<!--end-foo-bar->
foo-bar
must be a tag
that, when camel-cased,
matches a property name in the data
for the mustache template
this document is generated from.
If you want to change
the structure of the document,
you must make your changes
to scripts/api-docs.mustache
rather than in this document directly.