Authorisation

User-restricted endpoints

These endpoints require specific authorisation from the end user. They generally give access to secure data.

We use the open standard OAuth 2.0 with the Authorization Code Grant. This lets the end user grant authority to your application to interact with HMRC on their behalf, without sharing their access credentials. We are able to support PKCE for this grant-type, though you are not required to use it.

The end user authenticates directly with us using their HMRC sign in details, and grants authority for specific scopes.

We then issue an OAuth 2.0 access token that’s specific to the end user. Your application passes the access token in subsequent API requests to user-restricted endpoints.

There are separate HMRC sign in details for individuals, agents and organisations. For individuals and organisations, the access token only gives access to the end user’s own data. For agents the access token gives access to their clients’ data.

Authorisation rules for specific API endpoints are given in the API documentation.

The access token lasts for 4 hours. When it expires, it can be refreshed using a single-use refresh token. After 18 months you can no longer refresh the access token and the end user must grant authority again.

For a working example, see the user-restricted endpoint tutorial.

Getting an OAuth 2.0 access token

The authorisation user journey is an important part of our security, and may be changed without notice.

Warning You must not alter this journey in any way.

1. Request authorisation

  1. Send your user to our authorisation endpoint in-page link.
  2. We display a start page that explains the authorisation process.
  3. We prompt the user to sign in using their HMRC sign in details.
  4. The user is taken through 2-Step Verification (2SV).
  5. The user may be asked to confirm their identity. This depends on the user type, the specific API scopes being requested and whether or not the user has previously confirmed their identity.
  6. The user is asked to grant your application the authority to access certain scopes.

The following diagram illustrates the process:

API user auth journey
The example URL shown below is for the sandbox environment only. In the production environment you should use https://www.tax.service.gov.uk
Syntax
curl -X GET "https://test-www.tax.service.gov.uk/oauth/authorize?\
response_type=code\
&client_id=[YOUR-CLIENT-ID]\
&scope=[REQUESTED-SCOPE]\
&state=[STATE]\
&redirect_uri=[YOUR-REDIRECT-URI]\
&code_challenge=[CODE-CHALLENGE]\
&code_challenge_method=[CODE-CHALLENGE-METHOD]"

Example
curl -X GET "https://test-www.tax.service.gov.uk/oauth/authorize?\
response_type=code\
&client_id=Hf8sfkiUkYp9I3_R10qSnZ2ZUvoa\
&scope=scope_1+scope_2+scope_3\
&state=30de877c-ee2f-15db-8314-0800200c9a66\
&redirect_uri=https://www.example.com/auth-redirect\
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM\
&code_challenge_method=S256"

Warning Do not include your client secret in this request.
Authorise endpoint query parameters and descriptions
Parameter Description
response_type The OAuth 2.0 response type. Currently the only acceptable value is code.
client_id The Client ID for your application.
scope A space-delimited list of scopes you would like to have permission to access on behalf of your user. Must be URL-encoded, so spaces must be represented as either %20 or +.
state (optional) An opaque value used to maintain state between the request and callback and to prevent tampering as described in the OAuth 2.0 specification. This is passed back to your application via the redirect_uri.
redirect_uri The URI that we use to send users back to your application after successful (or unsuccessful) authorisation.

This must match one of the redirect URIs you specified when you created your application.

For more details see our reference guide.
code_challenge (optional) The PKCE code_challenge is used to ensure that the subsequently-issued access token is not intercepted. This is mandatory if code_challenge_method is provided.
code_challenge_method (optional) The PKCE code_challenge_method is used to transform the code_verifier to the code_challenge. This must have a value of S256. This is mandatory if code_challenge is provided.
Error scenarios

If there are any issues with your call to our authorisation endpoint, we return an HTTP error status to your user’s browser.

Any errors not listed are probably not from us. One possible cause is a network access issue.

The error codes listed are fixed, but the associated error messages may change without notice.
Error scenarios
Error scenario HTTP status Error code Error message
Client ID is missing 400 (Bad Request) invalid_request client_id is required
Client ID is invalid 400 (Bad Request) invalid_request client_id is invalid
Redirect URI is missing 400 (Bad Request) invalid_request redirect_uri is required
Redirect URI is invalid 400 (Bad Request) invalid_request redirect_uri is invalid
Response Type is missing 400 (Bad Request) invalid_request response_type is required
Response Type is invalid 400 (Bad Request) unsupported_response_type response_type must be 'code'
Scope is missing 400 (Bad Request) invalid_request scope is required
Scope is invalid 400 (Bad Request) invalid_scope scope is invalid
Client secret was included in the request 400 (Bad Request) invalid_request client_secret should NOT be present
PKCE Code Challenge cannot be empty 400 (Bad Request) invalid_request code_challenge if present, cannot be empty
PKCE Code Challenge Method, must be S256 400 (Bad Request) invalid_request code_challenge_method, if present, must be S256
PKCE Code Challenge Method should be present when Code Challenge is present 400 (Bad Request) invalid_request code_challenge_method should be present when code_challenge is present
PKCE Code Challenge should be present when Code Challenge Method is present 400 (Bad Request) invalid_request code_challenge should be present when code_challenge_method is present
Unexpected error occurred 500 (Internal Server Error) server_error Various
Browser support

For details of which browsers we support for the authorisation journey see OAuth 2.0 browser support, especially if you use an embedded browser.

2. Receive authorisation results

You need to create an endpoint in your application to receive the authorisation results, which needs to support an HTTP GET to the redirect URI you specified in step 1.

We’ll redirect the user’s browser back to your endpoint once the user has granted your application the requested authority.

Your endpoint must support the following query parameters:

Parameter Description
code The authorisation code, if authorisation is successful.
This is a single-use token that will expire after 10 minutes.
state The value of the state parameter you provided in the authorisation request, whether authorisation is successful or not.
error Always access_denied, if authorisation failed.
error_description Human readable description of the error, if authorisation failed, for example, “user denied the authorization”.
error_code Error code, if authorisation failed, for example, USER_DENIED_AUTHORIZATION.
The full list of error codes can change over time, so we recommend you do not cater for specific error codes.

Example of a redirect we issue after a successful authorisation:

https://www.example.com/auth-redirect?code=6589c5d9fc4b9872b1f9013583c2f39d&state=30de877c-ee2f-15db-8314-0800200c9a66"

Example of a redirect we issue after an unsuccessful authorisation:

https://www.example.com/auth-redirect?error=access_denied&error_description=user+denied+the+authorization&error_code=USER_DENIED_AUTHORIZATION&state=30de877c-ee2f-15db-8314-0800200c9a66

3. Exchange authorisation code for access token

When you get the authorisation code, you must exchange this for an access token within 10 minutes.

Do this via a POST to our token endpoint.

Include the request parameters in the request body, not as request headers.
The example URLs shown below are for the sandbox environment only. In the production environment you should use https://api.service.hmrc.gov.uk
Example request
curl -X POST -H "content-type:application/x-www-form-urlencoded" --data \
"client_secret=[YOUR-CLIENT-SECRET]\
&client_id=[YOUR-CLIENT-ID]\
&grant_type=authorization_code\
&redirect_uri=[YOUR-REDIRECT-URI]\
&code=[AUTHORIZATION-CODE]" \
&code_verifier=[CODE-VERIFIER]" \
https://test-api.service.hmrc.gov.uk/oauth/token

Token endpoint request body parameters and descriptions
Parameter Description
client_secret One of the client secrets for your application.
client_id The Client ID for your application.
grant_type The OAuth 2.0 grant type. Currently the only acceptable value is authorization_code
redirect_uri The same redirect URI you used to call the authorisation endpoint.

For more details see our reference guide.
code The authorisation code you received from us in the previous step.
code_verifier (optional) The PKCE code_verifier is mandatory if code_challenge was provided in the call to /authorize.

The response contains the access token used for calling the APIs and a refresh token used to obtain a new access token once the current one expires.

Example response
{
  "access_token": "QGbWG8KckncuwwD4uYXgWxF4HQvuPmrmUqKgkpQP",
  "token_type": "bearer",
  "expires_in": 14400,
  "refresh_token": "unJkSs5cvs8CS9E4DLvTkNhcRBq9BwUPm23cr3pF",
  "scope": "read:employment"
}

Error scenarios

If there are any issues with your call to our token endpoint, we return an HTTP error status.

Errors not listed are probably not from us. One possible cause is a network access issue, for example your network might allow GET requests but not POST requests.

The error codes listed are fixed, but the associated error messages can change without notice.
Error scenarios
Error scenario HTTP status Error code Error message
Client ID is missing 400 (Bad Request) invalid_request client_id is required
Client ID is invalid 401 (Unauthorized) invalid_client invalid client id or secret
Client Secret is missing 400 (Bad Request) invalid_request client_secret is required
Client Secret is invalid 401 (Unauthorized) invalid_client invalid client id or secret
Grant Type is missing 400 (Bad Request) invalid_request grant_type is required
Grant Type is invalid 400 (Bad Request) invalid_request unsupported grant_type
Redirect URI is missing 400 (Bad Request) invalid_request redirect_uri is required
Redirect URI is invalid 400 (Bad Request) invalid_request redirect_uri is invalid
Code is missing (for example because authorisation failed in step 2) 400 (Bad Request) invalid_request code is required for given grant_type
Code is invalid 400 (Bad Request) invalid_request code is invalid
PKCE Code Verifier wasn't expected as no Code Challenge was provided when requesting an authorization code 400 (Bad Request) invalid_request code_verifier is not expected
PKCE Code Verifier was expected but none was supplied 400 (Bad Request) invalid_request code_verifier is expected when code_challenge was supplied
PKCE Code Verifier is made up of fewer than 43, more than 128, or invalid characters 400 (Bad Request) invalid_request code_verifier must contain valid characters of length between 43 and 128
PKCE Code Verifier does not correlate to Code Challenge 400 (Bad Request) invalid_grant code_verifier is invalid
Unexpected error occurred 500 (Internal Server Error) server_error Various

4. Call an API

You can now call an API using the access_token we issued. Do this with an Authorization header containing this access_token as an OAuth 2.0 Bearer Token with the correct API scope.

Example request
curl -X GET https://test-api.service.hmrc.gov.uk/hello/user \
-H "Accept: application/vnd.hmrc.1.0+json" \
-H "Authorization: Bearer [ACCESS-TOKEN]"

5. Refreshing an access token

A user's access_token expires after 4 hours.

If the user's access_token has expired, calls from your application to an API will receive a response with an HTTP status code of 401 (Unauthorized) and an error code of INVALID_CREDENTIALS.

To refresh the access_token, submit the expired token’s corresponding refresh_token to our token endpoint using grant_type of refresh_token.

You can only use a refresh_token once. When you refresh an access_token, it invalidates the original access_token immediately if it has not already expired.

Be careful to avoid creating any race conditions when refreshing access tokens if your application supports concurrent API access.

Example request
curl -X POST -H "content-type: application/x-www-form-urlencoded" --data \
"client_secret=[YOUR-CLIENT-SECRET]\
&client_id=[YOUR-CLIENT-ID]\
&grant_type=refresh_token\
&refresh_token=[REFRESH-TOKEN]" \
https://test-api.service.hmrc.gov.uk/oauth/token

Example response
{
  "access_token": "unJkSs5cvs8CS9E4DLvTkNhcRBq9BwUPm23cr3pF",
  "token_type": "bearer",
  "expires_in": 14400,
  "refresh_token": "jPtmQuLtKmLhGURk8CmR2sWPmffBhDhPyFEEF4ay"
}

Error scenarios

If there are any issues with your call to our token endpoint, we return an HTTP error status.

Errors not listed are probably not from us. One possible cause is a network access issue.

Error scenarios
Error scenario HTTP status Error code
Client ID is missing 400 (Bad Request) invalid_request
Client ID is invalid 401 (Unauthorized) invalid_client
Client Secret is missing 400 (Bad Request) invalid_request
Client Secret is invalid 401 (Unauthorized) invalid_client
Grant Type is missing 400 (Bad Request) invalid_request
Grant Type is invalid 400 (Bad Request) invalid_request
Refresh Token is missing 400 (Bad Request) invalid_request
Refresh Token is invalid 400 (Bad Request) invalid_grant
Refresh operation is already in progress 400 (Bad Request) invalid_request
Unexpected error occurred 500 (Internal Server Error) server_error

Requesting a new token

Unless revoked earlier by the user, or tampered with, the authorisation granted to your application expires after 18 months, and you can no longer refresh the user's access_token.

If the user's refresh_token has expired, calls from your application to our token endpoint will return a response with an HTTP status code of 400 (Bad Request) and an error code of invalid_grant.

When this happens, your application must send the user back through the full process for Getting an OAuth 2.0 access token in-page link.

For a working example, see the user-restricted endpoint tutorial.

Revoking authority

A user can revoke the authority granted to your application at any time using the Manage authorised applications online service.

Agents with multiple accounts

Some agent organisations have more than one set of HMRC sign in details, and their client relationships are spread across those accounts. There are a few ways to handle this:

  • If the accounts belong to the same organisation, the agent can manage client relationships themselves using the HMRC online service.
  • If the accounts belong to different organisations (for example due to a merger), in some cases the agent can ask us to merge their accounts.
  • Your application may hold multiple OAuth 2.0 access tokens for the agent, but you must take care to use the correct token for each client when calling our APIs. Using the wrong access token results in an HTTP status code of 401 (Unauthorized).

OAuth 2.0 for installed applications

Our OAuth 2.0 implementation supports applications that are installed on a user's device, as long as it can access the system browser or an embedded browser.

The Redirect URI determines how the authorization_code is returned to your application.

Where your application is running on a remote web server, your Redirect URI returns the authorization_code to that server. You can then centrally manage your authorisation tokens.

In distributed applications, where your application is installed on a user's device and there's no centralised web server, you have the following options for a Redirect URI:

http://localhost:[PORT]

The authorization_code is returned to a web server running on the client at the specified port.

This may not always be suitable, for example where a firewall stops your client from listening on a HTTP port.

We recommend this approach for any installed application that's supported by the client configuration.

urn:ietf:wg:oauth:2.0:oob

The authorization_code is rendered in the title of a HTML page where you can parse the DOM to retrieve the code. You can then programmatically close the window before the user sees the rendered web page.

If your application can't parse the DOM or close the window, the HTML page renders the authorization_code along with a message asking the user to copy the code and paste it into your application, before closing the window.

urn:ietf:wg:oauth:2.0:oob:auto

The authorisation code is rendered in the title of a HTML page. The user sees a message asking them to close the browser window.

Use this if your application can detect that the page has loaded and parse the DOM to retrieve the code from the title, but can't close the window.