Access Token

Overview

The Access Token, commonly referred to as access_token in code samples, is a credential that can be used by a client to access an API. The access_token can be any type of token (such as an opaque string, or a JWT) and is meant for the API. The purpose of the access_token is to inform the API that the bearer of this token has been authorized to access the API and perform specific actions (as specified by the scope that has been granted). The access_token should be used as a Bearer credential and transmitted in an HTTP Authorization header to the API.

Access Tokens at Auth0

Auth0 currently generates access tokens in two formats:

  • As opaque strings, when YOUR_AUTH0_DOMAIN/userinfo is the audience.
  • As a JSON Web Token (JWT) when a custom API is specified as the audience.

The audience is a parameter which is set during authorization. It contains the unique identifier of the target API.

When a custom API audience is specified along with an openid scope, an access token is generated that will be valid for both the /userinfo endpoint and for the custom API.

Both the client and the API will also need to be using the same signing algorithm (RS256/HS256) in order to get and use a properly formed JWT access token.

The client signing algorithm can be specified in the Dashboard under the client's settings -> Advanced Settings -> Oauth.

Token Signing Algorithm - Client

When setting up an API in the Dashboard, the signing algorithm can also be specified.

Token Signing Algorithm - API

The important thing to remember is that the client should not be depending on the access token to be any specific format, but instead should treat the access token as opaque.

How to get an access token

Access tokens are issued via Auth0's OAuth 2.0 endpoints: /authorize and /oauth/token. You can use any OAuth 2.0-compatible library to obtain access tokens. If you do not already have a preferred OAuth 2.0 library, Auth0 provides libraries for many languages and frameworks that work seamlessly with our endpoints.

Using the Authentication API

How to use an access token

Access tokens are typically obtained in order to access user-owned resources. For example, a Calendar client needs access to a Calendar API in the cloud in order to read the user's scheduled events and create new events.

Such access is requested by the client and granted by the user, using the Authorize endpoint.

https://YOUR_AUTH0_DOMAIN/authorize?
  audience=api.calendar&
  scope=read write&
  response_type=token&
  client_id={account.clientId}&
  redirect_uri=https://YOUR_APP/callback&
  nonce={CRYPTOGRAPHIC_NONCE}
  state={OPAQUE_VALUE}

In this case the user will be prompted to permit read and write access (scope=read write). If allowed, an access token will be issued to the client, which the client can then use when making requests to the Calendar API. If consent has already been granted by the user, no consent dialog will be displayed and the access token will be issued without additional prompts.

Also, the consent dialog might be displayed again if the access level changes. For example, if the user has granted read access but the functionality changes so write access is required as well, the user will have to use the consent dialog to grant the additional access.

In some cases, consent can also be pre-configured administratively. This typically occurs when the user is an employee, and there are a set of company-specific applications that are always allowed access to employee data.

Server-to-server interactions

Access tokens can also be issued directly to clients. Such scenarios involve server-to-server interactions. In this case the user does not need to authenticate.

For example, a reverse geocoding API that accepts latitude/longitude coordinates and returns a readable place name does not access user-owned data. In such cases a backend server needs to call the geocoding API in order to perform the translation.

Server-to-server access tokens can be obtained using the Client Credentials flow. In order to get a token using this flow, the client has to provide its credentials (client_id, client_secret).


curl --request POST \
  --url 'https://YOUR_AUTH0_DOMAIN/oauth/token' \
  --header 'content-type: application/json' \
  --data '{"grant_type":"client_credentials","client_id": "YOUR_CLIENT_ID","client_secret": "YOUR_CLIENT_SECRET","audience": "https://api.example.com/geocoding/v1/"}'
var client = new RestClient("https://YOUR_AUTH0_DOMAIN/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/json");
request.AddParameter("application/json", "{\"grant_type\":\"client_credentials\",\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"audience\": \"https://api.example.com/geocoding/v1/\"}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io/ioutil"
)

func main() {

	url := "https://YOUR_AUTH0_DOMAIN/oauth/token"

	payload := strings.NewReader("{\"grant_type\":\"client_credentials\",\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"audience\": \"https://api.example.com/geocoding/v1/\"}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("content-type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
HttpResponse<String> response = Unirest.post("https://YOUR_AUTH0_DOMAIN/oauth/token")
  .header("content-type", "application/json")
  .body("{\"grant_type\":\"client_credentials\",\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"audience\": \"https://api.example.com/geocoding/v1/\"}")
  .asString();
var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://YOUR_AUTH0_DOMAIN/oauth/token",
  "method": "POST",
  "headers": {
    "content-type": "application/json"
  },
  "processData": false,
  "data": "{\"grant_type\":\"client_credentials\",\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"audience\": \"https://api.example.com/geocoding/v1/\"}"
}

$.ajax(settings).done(function (response) {
  console.log(response);
});
var request = require("request");

var options = { method: 'POST',
  url: 'https://YOUR_AUTH0_DOMAIN/oauth/token',
  headers: { 'content-type': 'application/json' },
  body: 
   { grant_type: 'client_credentials',
     client_id: 'YOUR_CLIENT_ID',
     client_secret: 'YOUR_CLIENT_SECRET',
     audience: 'https://api.example.com/geocoding/v1/' },
  json: true };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"content-type": @"application/json" };
NSDictionary *parameters = @{ @"grant_type": @"client_credentials",
                              @"client_id": @"YOUR_CLIENT_ID",
                              @"client_secret": @"YOUR_CLIENT_SECRET",
                              @"audience": @"https://api.example.com/geocoding/v1/" };

NSData *postData = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:nil];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://YOUR_AUTH0_DOMAIN/oauth/token"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://YOUR_AUTH0_DOMAIN/oauth/token",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "{\"grant_type\":\"client_credentials\",\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"audience\": \"https://api.example.com/geocoding/v1/\"}",
  CURLOPT_HTTPHEADER => array(
    "content-type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
import http.client

conn = http.client.HTTPSConnection("")

payload = "{\"grant_type\":\"client_credentials\",\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"audience\": \"https://api.example.com/geocoding/v1/\"}"

headers = { 'content-type': "application/json" }

conn.request("POST", "/YOUR_AUTH0_DOMAIN/oauth/token", payload, headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://YOUR_AUTH0_DOMAIN/oauth/token")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/json'
request.body = "{\"grant_type\":\"client_credentials\",\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"audience\": \"https://api.example.com/geocoding/v1/\"}"

response = http.request(request)
puts response.read_body
import Foundation

let headers = ["content-type": "application/json"]
let parameters = [
  "grant_type": "client_credentials",
  "client_id": "YOUR_CLIENT_ID",
  "client_secret": "YOUR_CLIENT_SECRET",
  "audience": "https://api.example.com/geocoding/v1/"
]

let postData = NSJSONSerialization.dataWithJSONObject(parameters, options: nil, error: nil)

var request = NSMutableURLRequest(URL: NSURL(string: "https://YOUR_AUTH0_DOMAIN/oauth/token")!,
                                        cachePolicy: .UseProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.HTTPMethod = "POST"
request.allHTTPHeaderFields = headers
request.HTTPBody = postData

let session = NSURLSession.sharedSession()
let dataTask = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    println(error)
  } else {
    let httpResponse = response as? NSHTTPURLResponse
    println(httpResponse)
  }
})

dataTask.resume()

The result will be an access token that can be used to make requests to the geocoding API.

HTTP/1.1 200 OK
Content-Type: application/json
{
  "access_token": "eyJz93a...k4laUWw",
  "token_type":"Bearer",
  "expires_in":86400
}

In order to obtain this access token, the client must first have permission to access the geocoding API. This is typically done by requesting access from the administrator of the geocoding API.

For details on how to set up a Client Credentials Grant in Auth0 refer to Setting up a Client Credentials Grant using the Management Dashboard.

Add Custom Claims

You can add custom claims to your access token (or ID Token) using Rules.

The claim name must conform to a namespaced format, which basically means adding any non-Auth0 HTTP or HTTPS URL as a prefix. The Auth0 namespaces you cannot use are auth0.com, webtask.io and webtask.run. The format you should follow is this: http://my-namespace/claim-name.

For more information on the namespaced format of custom claims, refer to User profile claims and scope.

For an example of how to add a custom claim, refer to Add Custom Claims.

Lifetime

The token lifetime can be controlled on a per-API basis. The validity period can be increased or decreased based on the security requirements of each API.

To configure the amount of time a token lives, use the Token Expiration (Seconds) field for your API at the Dashboard APIs section. The default value is 24 hours (86400 seconds).

Token Expiration - API

Once expired, an access token can no longer be used to access an API. In order to obtain access again, a new access token needs to be obtained. This can be done by repeating the OAuth flow used to obtain the initial access token.

In some situations, it is desirable to have permanent, ongoing access to an API without having to repeat an OAuth flow. This is often referred to as offline_access, and is possible with the use of a refresh token.

A refresh token is issued from the OAuth 2.0 endpoints along with the access token. When the access token expires, the refresh token can be used to obtain a fresh access token with the same permissions, without further involvement from a user.

Note that offline access is enabled as a policy of the API the access token grants access to. This is a setting that can be altered in the Dashboard under the APIs section.

Offline Access - API

If the API does not permit offline access, a refresh token will not be issued. In such circumstances, the OAuth flow must be repeated in order to obtain a new access token.

For more information on refresh tokens and how to use them refer to: Refresh Token.

Revoke access token

Revoking access tokens is not supported at the moment. The best way to control this is to set the validity period of the token, according to the security requirements of the API. For example, an access token that accesses a banking API should probably expire much faster than one that accesses a ToDo API.

Using Access Tokens with Custom APIs

JSON Web Tokens

Auth0 creates access tokens in JWT format for custom APIs. JWTs contain three parts: a header, a set of claims, and a signature:

  • The header contains metadata about the type of token and the cryptographic algorithms used to secure its contents.
  • The set of claims contains verifiable security statements such as the identity of the user and the permissions they are allowed.
  • The signature is used to validate that the token is trustworthy and has not been tampered with.

Authorize Access Tokens

Once a client has obtained an access token, it will include that token as a credential when making API requests.

GET /calandar/v1/events
Host​: api.example.com

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2V4YW1wbGUuYXV0aDAuY29tLyIsImF1ZCI6Imh0dHBzOi8vYXBpLmV4YW1wbGUuY29tL2NhbGFuZGFyL3YxLyIsInN1YiI6InVzcl8xMjMiLCJpYXQiOjE0NTg3ODU3OTYsImV4cCI6MTQ1ODg3MjE5Nn0.CA7eaHjIHz5NxeIJoFK9krqaeZrPLwmMmgI_XiQiIkQ

The token in this example decodes to the following claims:

{
  "alg": "RS256",
  "typ": "JWT"
}
.
{
  "iss": "https://example.auth0.com/",
  "aud": "https://api.example.com/calandar/v1/",
  "sub": "usr_123",
  "scope": "read write",
  "iat": 1458785796,
  "exp": 1458872196
}

Before permitting access to the API using this token, the API must verify the token using the following steps:

  1. Check that the JWT is well formed.
  2. Check the signature.
  3. Validate the standard claims (specifically the exp, iss and aud claims)
  4. Check the Client permissions (scopes)

For a more detailed description of the process of verifying access tokens, please refer to Verify Access Tokens.

If any of these checks fail, the token is invalid and the request should be rejected.

Once these checks have been performed successfully, the API can be assured that:

  • The token was issued by Auth0.
  • The token was issued to an application being operated by the user with an identifier of usr_123.
  • The user granted the application access to read and write his or her calendar.

The API can now process the request, allowing the application to read and write to user usr_123's calendar.