Skip to content
This repository has been archived by the owner on Apr 3, 2019. It is now read-only.

Latest commit

 

History

History
593 lines (446 loc) · 19.9 KB

api.md

File metadata and controls

593 lines (446 loc) · 19.9 KB

Firefox Accounts OAuth Server API

Overview

URL Structure

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.

Errors

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

API Endpoints

GET /v1/client/:id

This endpoint is for the fxa-content-server to retrieve information about a client to show in its user interface.

Request Parameters

  • id: The client_id of a client asking for permission.

Example:

curl -v "https://oauth.accounts.firefox.com/v1/client/5901bd09376fadaa"

Response

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 /v1/clients

Get a list of all registered clients.

Required scope: oauth

Request

Example:

curl -v \
-H "Authorization: Bearer 558f9980ad5a9c279beb52123653967342f702e84d3ab34c7f80427a6a37e2c0" \
"https://oauth.accounts.firefox.com/v1/clients"

Response

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
    }
  ]
}

POST /v1/client

Register a new client (FxA relier).

Required scope: oauth

Request Parameters

  • 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
}'

Response

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
}

POST /v1/client/:id

Update the details of a client. Any parameter not included in the request will stay unchanged.

Required scope: oauth

Request Parameters

  • 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",
}'

Response

A valid response will have a 200 status code and empty object {}.

DELETE /v1/client/:id

Delete a client. It will be no more. Zilch. Nada. Nuked from orbit.

Required scope: oauth

Request Parameters

Example:

curl -v \
-X DELETE \
-H "Authorization: Bearer 558f9980ad5a9c279beb52123653967342f702e84d3ab34c7f80427a6a37e2c0" \
"https://oauth.accounts.firefox.com/v1/client/5901bd09376fadaa"

Response

A valid response will have a 204 response code and an empty body.

POST /v1/developer/activate

Register an oauth developer.

Required scope: oauth

Request Parameters

  • None

Response

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"}

GET /v1/authorization

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.

Request Parameters

  • 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 scope openid, this will be an OpenID Connect authentication request.
  • access_type: Optional. If provided, should be online or offline. 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 be email, signup, signin, or force_auth. Send to improve the user experience.
    • If unspecified then Firefox Accounts will try choose intelligently between signin and signup 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 in email.
  • email: Optional if action is email, signup or signin. Required if action is force_auth.
    • if action is email, 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 is signup or signin, the email address will be pre-filled into the account form, but the user is free to change it.
    • If action is signin, the literal string blank will force the user to enter an email address and the last signed in email address will be ignored.
    • If action is signin and no email address is specified, the last signed in email address will be used as the default.
    • If action is force_auth, the user is unable to modify the email address and is unable to sign up if the address is not registered.

Example:

curl -v "https://oauth.accounts.firefox.com/v1/authorization?client_id=5901bd09376fadaa&state=1234&scope=profile:email&action=signup"

POST /v1/authorization

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.

Request Parameters

  • 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 either code or token. code is the default. token means the implicit grant is desired, and requires that the client have special permission to do so.
  • ttl: Optional if response_type=token, forbidden if response_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 the expires_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 of offline will generate a refresh token along with the access token.
  • code_challenge_method: Required if using PKCE. Must be S256, 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 as BASE64URL.
  • 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"
}'

Response

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"
}
Implicit Grant

If requesting an implicit grant (token), the response will match the /v1/token response.

POST /v1/token

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.

Request Parameters

  • ttl: (optional) Seconds that this access_token should be valid.

    The default and maximum value is 2 weeks.

  • grant_type: Either authorization_code, refresh_token, or urn: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:
    • if client is type publicClient:true and authorization_code:
      • code_verifier: Required if using PKCE.

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"
}'

Response

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 if grant_type=authorization_code and the original authorization request included access_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 with openid 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
}

POST /v1/destroy

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.

Request Parameters

  • 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"
}'

Response

A valid request will return an empty response, with a 200 status code.

POST /v1/verify

Attached services can post tokens to this endpoint to learn about which user and scopes are permitted for the token.

Request Parameters

  • 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"
}'

Response

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"
}

GET /v1/jwks

This endpoint returns the JWKs that are used for signing OpenID Connect id tokens.

Request

curl -v "https://oauth.accounts.firefox.com/v1/jwks"

Response

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"
  ]
}

POST /v1/post-keydata

This endpoint returns the required scoped key metadata.

Request

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"
}'

Response

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
  }
}