https://<server-url>/v1/<api-endpoint>
Note that:
- All API access must be over HTTPS.
- The URL embeds a version identifier "v1"; future revisions of this API may introduce new version numbers.
- The base URL of the server may be configured on a per-client basis.
Invalid requests will return 4XX responses. Internal failures will return 5XX. Both will include JSON responses describing the error.
Example error:
{
"code": 400, // matches the HTTP status code
"errno": 101, // stable application-level error number
"error": "Bad Request", // string description of error type
"message": "Unknown client"
}
The currently-defined error responses are:
status code | errno | description |
---|---|---|
400 | 101 | unknown client id |
400 | 102 | incorrect client secret |
400 | 103 | redirect_uri doesn't match registered value |
401 | 104 | invalid fxa assertion |
400 | 105 | unknown code |
400 | 106 | incorrect code |
400 | 107 | expired code |
400 | 108 | invalid token |
400 | 109 | invalid request parameter |
400 | 110 | invalid response_type |
401 | 111 | unauthorized |
403 | 112 | forbidden |
415 | 113 | invalid content type |
400 | 114 | invalid scopes |
400 | 115 | expired token |
500 | 999 | internal server error |
- GET /v1/authorization
- GET /v1/jwks
- POST /v1/authorization
- POST /v1/token
- POST /v1/destroy
- Clients
- Developers
- POST /v1/verify
- POST /v1/key-data
This endpoint is for the fxa-content-server to retrieve information about a client to show in its user interface.
id
: Theclient_id
of a client asking for permission.
Example:
curl -v "https://oauth.accounts.firefox.com/v1/client/5901bd09376fadaa"
A valid 200 response will be a JSON blob with the following properties:
name
: A string name of the client.image_uri
: A url to a logo or image that represents the client.redirect_uri
: The url registered to redirect to after successful oauth.trusted
: Whether the client is a trusted internal application.
Example:
{
"name": "Where's My Fox",
"image_uri": "https://mozilla.org/firefox.png",
"redirect_uri": "https://wheres.my.firefox.com/oauth",
"trusted": true
}
Get a list of all registered clients.
Required scope: oauth
Example:
curl -v \
-H "Authorization: Bearer 558f9980ad5a9c279beb52123653967342f702e84d3ab34c7f80427a6a37e2c0" \
"https://oauth.accounts.firefox.com/v1/clients"
A valid 200 response will be a JSON object with a property of clients
,
which contains an array of client objects.
Example:
{
"clients": [
{
"id": "5901bd09376fadaa",
"name": "Example",
"redirect_uri": "https://ex.am.ple/path",
"image_uri": "https://ex.am.ple/logo.png",
"can_grant": false,
"trusted": false
}
]
}
Register a new client (FxA relier).
Required scope: oauth
name
: The name of the client.redirect_uri
: The URI to redirect to after logging in.image_uri
: A URI to an image to show to a user when logging in.trusted
: Whether the client is a trusted internal application.can_grant
: A client needs permission to get implicit grants.
Example:
curl -v \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer 558f9980ad5a9c279beb52123653967342f702e84d3ab34c7f80427a6a37e2c0" \
"https://oauth.accounts.firefox.com/v1/client" \
-d '{
"name": "Example",
"redirect_uri": "https://ex.am.ple/path",
"image_uri": "https://ex.am.ple/logo.png",
"trusted": false,
"can_grant": false
}'
A valid 201 response will be a JSON blob with the following properties:
client_id
: The generated id for this client.client_secret
: The generated secret for this client. NOTE: This is the only time you can get the secret, because we only keep a hashed version.name
: A string name of the client.image_uri
: A url to a logo or image that represents the client.redirect_uri
: The url registered to redirect to after successful oauth.can_grant
: If the client can get implicit grants.trusted
: Whether the client is a trusted internal application.
Example:
{
"client_id": "5901bd09376fadaa",
"client_secret": "4ab433e31ef3a7cf7c20590f047987922b5c9ceb1faff56f0f8164df053dd94c",
"name": "Example",
"redirect_uri": "https://ex.am.ple/path",
"image_uri": "https://ex.am.ple/logo.png",
"can_grant": false,
"trusted": false
}
Update the details of a client. Any parameter not included in the request will stay unchanged.
Required scope: oauth
name
: The name of the client.redirect_uri
: The URI to redirect to after logging in.image_uri
: A URI to an image to show to a user when logging in.trusted
: Whether the client is a trusted internal application.can_grant
: A client needs permission to get implicit grants.
Example:
curl -v \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer 558f9980ad5a9c279beb52123653967342f702e84d3ab34c7f80427a6a37e2c0" \
"https://oauth.accounts.firefox.com/v1/client/5901bd09376fadaa" \
-d '{
"name": "Example2",
"redirect_uri": "https://ex.am.ple/path/2",
"image_uri": "https://ex.am.ple/logo2.png",
}'
A valid response will have a 200 status code and empty object {}
.
Delete a client. It will be no more. Zilch. Nada. Nuked from orbit.
Required scope: oauth
Example:
curl -v \
-X DELETE \
-H "Authorization: Bearer 558f9980ad5a9c279beb52123653967342f702e84d3ab34c7f80427a6a37e2c0" \
"https://oauth.accounts.firefox.com/v1/client/5901bd09376fadaa"
A valid response will have a 204 response code and an empty body.
Register an oauth developer.
Required scope: oauth
- None
A valid response will have a 200 status code and a developer object:
{"developerId":"f5b176ab5be5928d01d4bb0a6c182994","email":"d91c30a8@mozilla.com","createdAt":"2015-03-23T01:22:59.000Z"}
This endpoint starts the OAuth flow. A client redirects the user agent to this url. This endpoint will then redirect to the appropriate content-server page.
client_id
: The id returned from client registration.state
: A value that will be returned to the client as-is upon redirection, so that clients can verify the redirect is authentic.redirect_uri
: Optional. If supplied, a string URL of where to redirect afterwards. Must match URL from registration.scope
: Optional. A space-separated list of scopes that the user has authorized. This could be pruned by the user at the confirmation dialog. If this includes the scopeopenid
, this will be an OpenID Connect authentication request.access_type
: Optional. If provided, should beonline
oroffline
.offline
will result in a refresh_token being provided, so that the access_token can be refreshed after it expires.action
: Optional. If provided, should beemail
,signup
,signin
, orforce_auth
. Send to improve the user experience.- If unspecified then Firefox Accounts will try choose intelligently between
signin
andsignup
based on the user's browser state. email
triggers the email-first flow, which uses the email address to determine whether to display signup or signin.signin
triggers the signin flow.signup
triggers the signup flow.force_auth
requires the user to sign in using the address specified inemail
.
- If unspecified then Firefox Accounts will try choose intelligently between
email
: Optional ifaction
isemail
,signup
orsignin
. Required ifaction
isforce_auth
.- if
action
isemail
, the email address will be used to determine whether to display the signup or signin form, but the user is free to change it. - If
action
issignup
orsignin
, the email address will be pre-filled into the account form, but the user is free to change it. - If
action
issignin
, the literal stringblank
will force the user to enter an email address and the last signed in email address will be ignored. - If
action
issignin
and no email address is specified, the last signed in email address will be used as the default. - If
action
isforce_auth
, the user is unable to modify the email address and is unable to sign up if the address is not registered.
- if
Example:
curl -v "https://oauth.accounts.firefox.com/v1/authorization?client_id=5901bd09376fadaa&state=1234&scope=profile:email&action=signup"
This endpoint should be used by the fxa-content-server, requesting that we supply a short-lived code (currently 15 minutes) that will be sent back to the client. This code will be traded for a token at the token endpoint.
client_id
: The id returned from client registration.assertion
: A FxA assertion for the signed-in user.state
: A value that will be returned to the client as-is upon redirection, so that clients can verify the redirect is authentic.response_type
: Optional. If supplied, must be eithercode
ortoken
.code
is the default.token
means the implicit grant is desired, and requires that the client have special permission to do so.ttl
: Optional ifresponse_type=token
, forbidden ifresponse_type=code
. Indicates the requested lifespan in seconds for the implicit grant token. The value is subject to an internal maximum limit, so clients must check theexpires_in
result property for the actual TTL.redirect_uri
: Optional. If supplied, a string URL of where to redirect afterwards. Must match URL from registration.scope
: Optional. A string-separated list of scopes that the user has authorized. This could be pruned by the user at the confirmation dialog.access_type
: Optional. A value ofoffline
will generate a refresh token along with the access token.code_challenge_method
: Required if using PKCE. Must beS256
, no other value is accepted.code_challenge
: Required if using PKCE. A minimum length of 43 characters and a maximum length of 128 characters string, encoded asBASE64URL
.keys_jwe
: Optional. A JWE bundle to be returned to the client when it redeems the authorization code.
Example:
curl -v \
-X POST \
-H "Content-Type: application/json" \
"https://oauth.accounts.firefox.com/v1/authorization" \
-d '{
"client_id": "5901bd09376fadaa",
"assertion": "<assertion>",
"state": "1234",
"scope": "profile:email"
}'
A valid request will return a 200 response, with JSON containing the redirect
to follow. It will include the following query parameters:
code
: A string that the client will trade with the token endpoint. Codes have a configurable expiration value, default is 15 minutes. Codes are single use only.state
: The same value as was passed as a request parameter.
Example:
{
"redirect": "https://example.domain/path?foo=bar&code=4ab433e31ef3a7cf7c20590f047987922b5c9ceb1faff56f0f8164df053dd94c&state=1234"
}
If requesting an implicit grant (token), the response will match the /v1/token response.
After having received a code, the client sends that code (most likely a server-side request) to this endpoint, to receive a longer-lived token that can be used to access attached services for a particular user.
-
ttl
: (optional) Seconds that this access_token should be valid.The default and maximum value is 2 weeks.
-
grant_type
: Eitherauthorization_code
,refresh_token
, orurn:ietf:params:oauth:grant-type:jwt-bearer
.- If
authorization_code
:client_id
: The id returned from client registration.client_secret
: The secret returned from client registration.code
: A string that was received from the authorization endpoint.
- If
refresh_token
:client_id
: The id returned from client registration.client_secret
: The secret returned from client registration. This must not be set if the client is a public (PKCE) client.refresh_token
: A string that received from the token endpoint specifically as a refresh token.scope
: (optional) A subset of scopes provided to this refresh_token originally, to receive an access_token with less permissions.
- If
urn:ietf:params:oauth:grant-type:jwt-bearer
:assertion
: A signed JWT assertion. See Service Clients for more.
- if client is type
publicClient:true
andauthorization_code
:code_verifier
: Required if using PKCE.
- If
Example:
curl -v \
-X POST \
-H "Content-Type: application/json" \
"https://oauth.accounts.firefox.com/v1/token" \
-d '{
"client_id": "5901bd09376fadaa",
"client_secret": "20c6882ef864d75ad1587c38f9d733c80751d2cbc8614e30202dc3d1d25301ff",
"ttl": 3600,
"grant_type": "authorization_code",
"code": "4ab433e31ef3a7cf7c20590f047987922b5c9ceb1faff56f0f8164df053dd94c"
}'
A valid request will return a JSON response with these properties:
access_token
: A string that can be used for authorized requests to service providers.scope
: A string of space-separated permissions that this token has. May differ from requested scopes, since user can deny permissions.refresh_token
: (Optional) A refresh token to fetch a new access token when this one expires. Only will be present ifgrant_type=authorization_code
and the original authorization request includedaccess_type=offline
.expires_in
: Seconds until this access token will no longer be valid.token_type
: A string representing the token type. Currently will always be "bearer".auth_at
: An integer giving the time at which the user authenticated to the Firefox Accounts server when generating this token, as a UTC unix timestamp (i.e. seconds since epoch).id_token
: (Optional) If the authorization was requested withopenid
scope, then this property will contain the OpenID Connect ID Token.keys_jwe
: (Optional) Returns the JWE bundle that if the authorization request had one.
Example:
{
"access_token": "558f9980ad5a9c279beb52123653967342f702e84d3ab34c7f80427a6a37e2c0",
"scope": "profile:email profile:avatar",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "58d59cc97c3ca183b3a87a65eec6f93d5be051415b53afbf8491cc4c45dbb0c6",
"auth_at": 1422336613
}
After a client is done using a token, the responsible thing to do is to destroy the token afterwards. A client can use this route to do so.
token
- The hex string token.
Example:
curl -v \
-X POST \
-H "Content-Type: application/json" \
"https://oauth.accounts.firefox.com/v1/destroy" \
-d '{
"token": "558f9980ad5a9c279beb52123653967342f702e84d3ab34c7f80427a6a37e2c0"
}'
A valid request will return an empty response, with a 200 status code.
Attached services can post tokens to this endpoint to learn about which user and scopes are permitted for the token.
token
: A token string received from a client
Example:
curl -v \
-X POST \
-H "Content-Type: application/json" \
"https://oauth.accounts.firefox.com/v1/verify" \
-d '{
"token": "558f9980ad5a9c279beb52123653967342f702e84d3ab34c7f80427a6a37e2c0"
}'
A valid request will return JSON with these properties:
user
: The uid of the respective user.client_id
: The client_id of the respective client.scope
: An array of scopes allowed for this token.email
: DEPRECATED The email of the respective user.
Example:
{
"user": "5901bd09376fadaa076afacef5251b6a",
"client_id": "45defeda038a1c92",
"scope": ["profile:email", "profile:avatar"],
"email": "foo@example.com"
}
This endpoint returns the JWKs that are used for signing OpenID Connect id tokens.
curl -v "https://oauth.accounts.firefox.com/v1/jwks"
A valid response will return JSON of the keys
.
Example:
{
"keys": [
"alg": "RS256",
"use": "sig",
"kty": "RSA",
"kid": "2015.12.02-1",
"n":"xaQHsKpu1KSK-YEMoLzZS7Xxciy3esGrhrrqW_JBrq3IRmeGLaqlE80zcpIVnStyp9tbet2niYTemt8ug591YWO5Y-S0EgQyFTxnGjzNOvAL6Cd2iGie9QeSehfFLNyRPdQiadYw07fw-h5gweMpVJs8nTgS-Bcorlw9JQM6Il1cUpbP0Lt-F_5qrzlaOiTEAAb4JGOusVh0n-MZfKt7w0mikauMH5KfhflwQDn4YTzRkWJzlldXr1Cs0ZkYzOwS4Hcoku7vd6lqCUO0GgZvkuvCFqdVKzpa4CGboNdfIjcGVF4f1CTQaQ0ao51cwLzq1pgi5aWYhVH7lJcm6O_BQw",
"e":"AQAC"
]
}
This endpoint returns the required scoped key metadata.
curl -X POST \
https://oauth.accounts.firefox.com/v1/key-data \
-H 'cache-control: no-cache' \
-H 'content-type: application/json' \
-d '{
"client_id": "aaa6b9b3a65a1871",
"assertion": "eyJhbGciOiJSUzI1NiJ9.eyJwdWJsaWMta2V5Ijp7Imt0eSI6IlJTQSIsIm4iOiJvWmdsNkpwM0Iwcm5BVXppNThrdS1iT0RvR3ZuUGNnWU1UdXQ1WkpyQkJiazBCdWU4VUlRQ0dnYVdrYU5Xb29INkktMUZ6SXU0VFpZYnNqWGJ1c2JRRlQxOGREUkN6VVRubFlXdVZXUzhoSWhKc3lhZHJwSHJOVkI1VndmSlRKZVgwTjFpczBXcU1qdUdOc2VMLXluYnFjOVhueElncFJaai05QnZqY2ZKYXNOUTNZdHR3VHZVaFJOLVFGNWgxQkY1MnA2QmdOTVBvWmQ5MC1EU0xydlpseXp6MEh0Q2tFZnNsc013czVkR0ExTlZ1dEwtcGVDeU50VTFzOEtFaDlzcGxXeF9lQlFybTlYQU1kYXp5ZWR6VUpJU1UyMjZmQzhEUHh5c0ZreXpCbjlDQnFDQUpTNjQzTGFydUVDaS1rMGhKOWFmM2JXTmJnWmpSNVJ2NXF4THciLCJlIjoiQVFBQiJ9LCJwcmluY2lwYWwiOnsiZW1haWwiOiIwNjIxMzM0YzIwNjRjNmYzNmJlOGFkOWE0N2M1NTliY2FwaS5hY2NvdW50cy5maXJlZm94LmNvbSJ9LCJpYXQiOjE1MDY5Njk2OTU0MzksImV4cCI6MTUwNjk2OTY5NjQzOSwiZnhhLXZlcmlmaWVkRW1haWwiOiIzMjM2NzJiZUBtb3ppbGxhLmNvbSIsImlzcyI6ImFwaS5hY2NvdW50cy5maXJlZm94LmNvbSJ9.hFZd5zFheXOFrXKkJvw6Vpv2l7ctlxuBTvuh5f_jLPAjZoJ9ri-vaJjL_WYBFUvS2xHzfx3-ldxLddyTKwCDAJeB_NkOFL_WJSrMet9C7_Z1hH9HmydeXIT82xJmhrwzW-WOO4ibQvRbocEFiNujynKsg1gS8v0iiYjIX-0cXCrlkxkbVx_8EXJFKDDOGzK9v7Zq6D7gkhP-CHEaNYaTHMn65tLQtBS6snGdaXlxoGHMWmDL6STbnJzWa7sa4QwHf-AgT1rUkQQAUHNa_XLZ0FEzqiCPctMadlihiUZL2V6vxIDBS4mHUF4qj0FvIMJflivDnJVkRNijDuP-h-Lh_A~eyJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJvYXV0aC5meGEiLCJleHAiOjE1MDY5Njk2OTY0MzksImlzcyI6ImFwaS5hY2NvdW50cy5maXJlZm94LmNvbSJ9.M5xyk3RffucgaavjbUm7Eqnt47hzeGbGa2VR3jnVEIlRHfz5S25Qf3ngejwee7XECvIywbaKWeijXFOwS-EkB-7qP1gl4oNJjPmbnCk7S1lgckLWvdMIU-HLGKjrN6Mw76__LzvAbsusSeGmsvTCIVuOJ49Xs3tC1fLyB_re0QNpCcS6AUnJ1KOxIMEM3Om7ysNO5F_AqcD3PwlEti5lbwSk8iP5TWL12C2Nkb_6Hxze_mA1NZNAHOips9bF2J7oy1hqGoMYj1XYZrsyjpPWEuZQATAPlKSjbh1hq-UtDeT7DlwEmIbIUd3JA8qh1MkHKGgavd4fIMap0IPmr9rs4A",
"scope": "https://identity.mozilla.com/apps/sample-scope-can-scope-key"
}'
A valid response will return JSON the scoped key information for every scope that has scoped keys:
Example:
{
"https://identity.mozilla.com/apps/sample-scope-can-scope-key": {
"identifier": "https://identity.mozilla.com/apps/sample-scope-can-scope-key",
"keyRotationSecret": "0000000000000000000000000000000000000000000000000000000000000000",
"keyRotationTimestamp": 1506970363512
}
}