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 Authorisation Code Grant. This lets the end-user grant authority to your application to interact with Defra on their behalf, without sharing their access credentials.
The end-user authenticates directly with us using their Government Gateway account 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.
Authorisation rules for specific API endpoints are given in the API documentation.
The access token lasts for 1 hour. When it expires, it can be refreshed using a single-use refresh token. After 12 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.
- Request authorisation code from Defra token endpoint, providing authorisation token
- Returns authorisation code
- Request a bearer token, providing authorisation_code, client_id, etc.
- Returns an access_token and refresh_token
- Call the API with the access_token in the Authorisation header
- Returns secure data to the application
- Requests a new access_token, providing the refresh_token, client_id, etc.
- Return a new access_token and a new refresh_token
1. Request authorisation
- Send your user to our authorisation endpoint.
- We prompt the user to sign in using their Government Gateway account.
- 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.
- The user is asked to grant your application the authority to access certain scopes.
Syntax
https://gateway.trade.defra.gov.uk/uat/api/{tenant}/oauth2/v2.0/authorize? &client_id=[YOUR-CLIENT-ID] &response_type=[RESPONSE-TYPE] &redirect_uri=[REDIRECT_URI] &response_mode=[RESPONSE_MODE] &scope=[SCOPE] &state=[STATE] &code_challange=[CODE_CHALLANGE] &code_challange_method=[CODE_CHALLANGE_METHOD]
Example
https://gateway.trade.defra.gov.uk/uat/api/{tenant}/oauth2/v2.0/authorize?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&response_type=code
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&response_mode=query
&scope=https%3A%2F%2Fgateway.trade.defra.gov.uk%2Fplants.read%20api%3A%2F%2F
&state=12345
&code_challenge=YTFjNjI1OWYzMzA3MTI4ZDY2Njg5M2RkNmVjNDE5YmEyZGRhOGYyM2IzNjdmZWFhMTQ1ODg3NDcxY2Nl
&code_challenge_method=S256
Request parameters
Parameter | Required | Description |
---|---|---|
tenant | True | The tenant value in the path of the request can be used to control who can sign into the application. |
client_id | True | The Application (client) ID |
response_type | True | Must include code for the authorization code flow. |
redirect_uri | True | The redirect_uri of your app, where authentication responses can be sent and received by your app. It must exactly match one of the redirect_uris you registered in the portal, except it must be URL encoded. |
scope | True | A space-separated list of scopes that you want the user to consent to. |
response_mode | True | Specifies the method that should be used to send the resulting token back to your app. Can be one of the following: - query - fragment - form_post |
state | True | A value included in the request that will also be returned in the token response. It can be a string of any content that you wish. A randomly generated unique value is typically used for preventing cross-site request forgery attacks. |
prompt | True | Indicates the type of user interaction that is required. The only valid values at this time is consent. - prompt=consent will trigger the OAuth consent dialogue after the user signs in, asking the user to grant permissions to the app. |
code_challenge | True | Used to secure authorization code grants via Proof Key for Code Exchange (PKCE). Required if code_challenge_method is included. For more information, see the PKCE RFC. |
code_challenge_method | True | The method used to encode the code_verifier for the code_challenge parameter. This SHOULD be S256, but the spec allows the use of plain if for some reason the client cannot support SHA256. |
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 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 |
Code Challenge is missing | 400 (Bad Request) | invalid_request | code_challange is required |
Code Challenge is Invalid | 400 (Bad Request) | invalid_scode_challange | code_challange is invalid |
Code Challenge Method is missing | 400 (Bad Request) | invalid_request | code_challange_method is required |
Code Challenge Method is Invalid | 400 (Bad Request) | invalid_code_challange_method | code_challange_method is invalid |
Client secret was included in the request | 400 (Bad Request) | invalid_request | client_secret should NOT be 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 the authorisation is successful or not. |
Example of a redirect we issue after a successful authorisation:
GET https://www.example.com/auth-redirect?code=6589c5d9fc4b9872b1f9013583c2f39d&state=30de877c-ee2f-15db-8314-0800200c9a66
Example of a redirect we issue after an unsuccessful authorisation:
GET https://www.example.com/auth-redirect?error=access_denied
&error_description=the+user+canceled+the+authentication
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.defra.gov.uk
Example request
POST /{tenant}/oauth2/v2.0/token HTTP/1.1
Host: https://gateway.trade.defra.gov.uk/uat/api/oauth/token
Content-Type: application/x-www-form-urlencoded
client_id=[YOUR-CLIENT-ID]
&scope=[SCOPE]
&code=[CODE]
&redirect_uri=[YOUR-REDIRECT-URI]
&grant_type=[GRANT-TYPE]
&code_verifier=[CODE=VERFIRER]
&client_secret=[CLIENT-SECRET]
Parameter | Required | Description |
---|---|---|
tenant | True | The {tenant} value in the path of the request can be used to control who can sign into the application. The allowed values are common, organizations, consumers, and tenant identifiers. |
client_id | True | The Application (client) ID |
grant_type | True | Must be authorization_code for the authorization code flow. |
scope | True | A space-separated list of scopes. The scopes must all be from a single resource, along with OIDC scopes (profile, openid, email). |
code | True | The authorization_code that you acquired in the first leg of the flow. |
redirect_uri | True | The same redirect_uri value that was used to acquire the authorization_code. |
client_secret | True | The application secret that you created in the app registration portal for your app. You shouldn't use the application secret in a native app or single page app because client_secrets can't be reliably stored on devices or web pages. |
code_verifier | True | The same code_verifier that was used to obtain the authorization_code. Required if PKCE was used in the authorization code grant request. For more information, see the PKCE RFC. |
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",
"id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJhdWQiOiIyZDRkMTFhMi1mODE0LTQ2YTctOD..."
}
Parameter | Description |
---|---|
access_token | The requested access token. The app can use this token to authenticate to the secured resource, such as a web API. |
token_type | Indicates the token type value. The only type that Azure AD supports is Bearer |
expires_in | How long the access token is valid (in seconds). |
scope | The scopes that the access_token is valid for. Optional - this is non-standard, and if omitted the token will be for the scopes requested on the initial leg of the flow. |
refresh_token | An OAuth 2.0 refresh token. The app can use this token to acquire additional access tokens after the current access token expires. Refresh_tokens are long-lived and can be used to retain access to resources for extended periods of time. |
id_token | A JSON Web Token (JWT). The app can decode the segments of this token to request information about the user who signed in. The app can cache the values and display them, and confidential clients can use this for authorization. |
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 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 |
Code Verifier is missing | 400 (Bad Request) | invalid_request | Code_verifier is required for given grant_type |
Code Verifier is invalid | 400 (Bad Request) | invalid_request | 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://gateway.trade.defra.gov.uk/uat/api/hello/user \ -H "Accept: application/vnd.defra.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://gateway.trade.defra.gov.uk/uat/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 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_request.
When this happens, your application must send the user back through the full process for Getting an OAuth 2.0 access token.
Revoking authority
A user can revoke the authority granted to your application at any time using the Defra Developer Portal and APIs.
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 an 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 an 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 an 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 parsed the DOM to retrieve the code from the title, but can't close the window.