Refresh Token

A Refresh Token is a special kind of token that contains the information required to obtain a new access token or ID token.

Usually, a user will need a new access token only after the previous one expires, or when gaining access to a new resource for the first time.

Refresh tokens are subject to strict storage requirements to ensure that they are not leaked. Also, Refresh tokens can be revoked by the Authorization Server.

OIDC-conformant clients

The behaviour in this document is applicable to OIDC-conformant clients. A client can be configured as OIDC-conformant in two ways:

  1. By enabling the OIDC Conformant flag for a Client
  2. By passing an audience to the /authorize endpoint

For more information on our authentication pipeline, refer to Introducing OIDC Conformant Authentication.

Overview

The response of an authentication request can result in an access_token and/or an id_token being issued by Auth0. The access_token is used to make authenticated calls to a secured API, while the id_token contains user profile attributes represented in the form of claims. Both JWTs have an expiration date indicated by the exp claim (among other security measures, like signing).

A refresh token allows the application to request Auth0 to issue a new access_token or id_token directly, without having to re-authenticate the user. This will work as long as the refresh token has not been revoked.

Restrictions

You can only get a refresh token if you are implementing: Authorization Code Grant, Authorization Code Grant (PKCE) or Resource Owner Password Grant.

A Single Page Application (normally implementing Implicit Grant) should not under any circumstances get a refresh token. The reason for that is the sensitivity of this piece of information. You can think of it as user credentials, since a refresh token allows a user to remain authenticated essentially forever. Therefore you cannot have this information in a browser, it must be stored securely.

If you are implementing an SPA using Implicit Grant and you need to renew a token, the only secure option is to use Silent Authentication.

Another safeguard is that the API should allow offline access. This is configured via the Allow Offline Access switch on the API Settings. If the switch is disabled, Auth0 will not return a refresh token for this API, even if you included the offline_access scope.

Get a Refresh Token

To get a refresh token, you must include the offline_access scope when you initiate an authentication request through the authorize endpoint.

For example, if you are using Authorization Code Grant, the authentication request would look like the following:

https://YOUR_AUTH0_DOMAIN/authorize?
    audience={API_AUDIENCE}&
    scope=offline_access&
    response_type=code&
    client_id=YOUR_CLIENT_ID&
    redirect_uri=https://YOUR_APP/callback&
    state={OPAQUE_VALUE}

Once the user authenticates successfully, the client will be redirected to the redirect_uri, with a code as part of the URL: https://YOUR_APP/callback?code=BPPLN3Z4qCTvSNOy. You can exchange this code with an access token using the /oauth/token endpoint.


curl --request POST \
  --url 'https://YOUR_AUTH0_DOMAIN/oauth/token' \
  --header 'content-type: application/json' \
  --data '{"grant_type":"authorization_code","client_id": "YOUR_CLIENT_ID","client_secret": "YOUR_CLIENT_SECRET","code": "YOUR_AUTHORIZATION_CODE","redirect_uri": "https://YOUR_APP/callback"}'
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\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"https://YOUR_APP/callback\"}", 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\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"https://YOUR_APP/callback\"}")

	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\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"https://YOUR_APP/callback\"}")
  .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\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"https://YOUR_APP/callback\"}"
}

$.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: 'authorization_code',
     client_id: 'YOUR_CLIENT_ID',
     client_secret: 'YOUR_CLIENT_SECRET',
     code: 'YOUR_AUTHORIZATION_CODE',
     redirect_uri: 'https://YOUR_APP/callback' },
  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": @"authorization_code",
                              @"client_id": @"YOUR_CLIENT_ID",
                              @"client_secret": @"YOUR_CLIENT_SECRET",
                              @"code": @"YOUR_AUTHORIZATION_CODE",
                              @"redirect_uri": @"https://YOUR_APP/callback" };

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\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"https://YOUR_APP/callback\"}",
  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\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"https://YOUR_APP/callback\"}"

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\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"https://YOUR_APP/callback\"}"

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

let headers = ["content-type": "application/json"]
let parameters = [
  "grant_type": "authorization_code",
  "client_id": "YOUR_CLIENT_ID",
  "client_secret": "YOUR_CLIENT_SECRET",
  "code": "YOUR_AUTHORIZATION_CODE",
  "redirect_uri": "https://YOUR_APP/callback"
]

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 response should contain an access token and a refresh token.

{
  "access_token": "eyJz93a...k4laUWw",
  "refresh_token": "GEbRxBN...edjnXbL",
  "token_type": "Bearer"
}

If you are requesting a refresh_token for a mobile app using the corresponding Native Client (which is public) then you don't need to send the client_secret in the request since it's only needed for confidential clients.

Refresh tokens must be stored securely by an application since they allow a user to remain authenticated essentially forever.

For more information on how to implement this using Authorization Code Grant refer to Execute an Authorization Code Grant Flow. For other grants refer to API Authorization.

If the response did not include a refresh token, check that you comply with the Restrictions listed in this document.

Use a Refresh Token

To refresh your token, using the refresh_token you already got during authorization, make a POST request to the /oauth/token endpoint in the Authentication API, using grant_type=refresh_token.


curl --request POST \
  --url 'https://YOUR_AUTH0_DOMAIN/oauth/token' \
  --header 'content-type: application/json' \
  --data '{ "grant_type": "refresh_token", "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET", "refresh_token": "YOUR_REFRESH_TOKEN" }'
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\": \"refresh_token\", \"client_id\": \"YOUR_CLIENT_ID\", \"client_secret\": \"YOUR_CLIENT_SECRET\", \"refresh_token\": \"YOUR_REFRESH_TOKEN\" }", 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\": \"refresh_token\", \"client_id\": \"YOUR_CLIENT_ID\", \"client_secret\": \"YOUR_CLIENT_SECRET\", \"refresh_token\": \"YOUR_REFRESH_TOKEN\" }")

	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\": \"refresh_token\", \"client_id\": \"YOUR_CLIENT_ID\", \"client_secret\": \"YOUR_CLIENT_SECRET\", \"refresh_token\": \"YOUR_REFRESH_TOKEN\" }")
  .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\": \"refresh_token\", \"client_id\": \"YOUR_CLIENT_ID\", \"client_secret\": \"YOUR_CLIENT_SECRET\", \"refresh_token\": \"YOUR_REFRESH_TOKEN\" }"
}

$.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: 'refresh_token',
     client_id: 'YOUR_CLIENT_ID',
     client_secret: 'YOUR_CLIENT_SECRET',
     refresh_token: 'YOUR_REFRESH_TOKEN' },
  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": @"refresh_token",
                              @"client_id": @"YOUR_CLIENT_ID",
                              @"client_secret": @"YOUR_CLIENT_SECRET",
                              @"refresh_token": @"YOUR_REFRESH_TOKEN" };

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\": \"refresh_token\", \"client_id\": \"YOUR_CLIENT_ID\", \"client_secret\": \"YOUR_CLIENT_SECRET\", \"refresh_token\": \"YOUR_REFRESH_TOKEN\" }",
  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\": \"refresh_token\", \"client_id\": \"YOUR_CLIENT_ID\", \"client_secret\": \"YOUR_CLIENT_SECRET\", \"refresh_token\": \"YOUR_REFRESH_TOKEN\" }"

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\": \"refresh_token\", \"client_id\": \"YOUR_CLIENT_ID\", \"client_secret\": \"YOUR_CLIENT_SECRET\", \"refresh_token\": \"YOUR_REFRESH_TOKEN\" }"

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

let headers = ["content-type": "application/json"]
let parameters = [
  "grant_type": "refresh_token",
  "client_id": "YOUR_CLIENT_ID",
  "client_secret": "YOUR_CLIENT_SECRET",
  "refresh_token": "YOUR_REFRESH_TOKEN"
]

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()

Where:

  • grant_type: The type of grant to execute (the /token endpoint is used for various grants, for more information refer to the Authentication API). To refresh a token use refresh_token.
  • client_id: Your application's Client ID.
  • client_secret (optional): Your application's Client Secret. Only required for confidential clients.
  • refresh_token: The refresh token to use.

The response will include a new access_token, its type, its lifetime (in seconds), and the granted scopes. If the scope of the initial token included openid, then a new id_token will be in the response as well.

{
  "access_token": "eyJ...MoQ",
  "expires_in": 86400,
  "scope": "openid offline_access",
  "id_token": "eyJ...0NE",
  "token_type": "Bearer"
}

Rate limits

You should only ask for a new token if the access_token has expired or you want to refresh the claims contained in the id_token. For example, it's a bad practice to call the endpoint to get a new access_token every time you call an API. There are rate limits in Auth0 that will throttle the amount of requests to this endpoint that can be executed using the same token from the same IP.

Revoke a Refresh Token

Since refresh tokens never expire it is important to be able to revoke them. You can revoke a refresh token either by posting a revocation request to https://YOUR_AUTH0_DOMAIN/oauth/revoke or using the dashboard.

Use the API

To revoke a refresh token you can send a POST request to https://YOUR_AUTH0_DOMAIN/oauth/revoke.


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

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

func main() {

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

	payload := strings.NewReader("{ \"client_id\": \"YOUR_CLIENT_ID\", \"client_secret\": \"YOUR_CLIENT_SECRET\", \"token\": \"YOUR_REFRESH_TOKEN\" }")

	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/revoke")
  .header("content-type", "application/json")
  .body("{ \"client_id\": \"YOUR_CLIENT_ID\", \"client_secret\": \"YOUR_CLIENT_SECRET\", \"token\": \"YOUR_REFRESH_TOKEN\" }")
  .asString();
var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://YOUR_AUTH0_DOMAIN/oauth/revoke",
  "method": "POST",
  "headers": {
    "content-type": "application/json"
  },
  "processData": false,
  "data": "{ \"client_id\": \"YOUR_CLIENT_ID\", \"client_secret\": \"YOUR_CLIENT_SECRET\", \"token\": \"YOUR_REFRESH_TOKEN\" }"
}

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

var options = { method: 'POST',
  url: 'https://YOUR_AUTH0_DOMAIN/oauth/revoke',
  headers: { 'content-type': 'application/json' },
  body: 
   { client_id: 'YOUR_CLIENT_ID',
     client_secret: 'YOUR_CLIENT_SECRET',
     token: 'YOUR_REFRESH_TOKEN' },
  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 = @{ @"client_id": @"YOUR_CLIENT_ID",
                              @"client_secret": @"YOUR_CLIENT_SECRET",
                              @"token": @"YOUR_REFRESH_TOKEN" };

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

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://YOUR_AUTH0_DOMAIN/oauth/revoke"]
                                                       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/revoke",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "{ \"client_id\": \"YOUR_CLIENT_ID\", \"client_secret\": \"YOUR_CLIENT_SECRET\", \"token\": \"YOUR_REFRESH_TOKEN\" }",
  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 = "{ \"client_id\": \"YOUR_CLIENT_ID\", \"client_secret\": \"YOUR_CLIENT_SECRET\", \"token\": \"YOUR_REFRESH_TOKEN\" }"

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

conn.request("POST", "/YOUR_AUTH0_DOMAIN/oauth/revoke", 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/revoke")

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 = "{ \"client_id\": \"YOUR_CLIENT_ID\", \"client_secret\": \"YOUR_CLIENT_SECRET\", \"token\": \"YOUR_REFRESH_TOKEN\" }"

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

let headers = ["content-type": "application/json"]
let parameters = [
  "client_id": "YOUR_CLIENT_ID",
  "client_secret": "YOUR_CLIENT_SECRET",
  "token": "YOUR_REFRESH_TOKEN"
]

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

var request = NSMutableURLRequest(URL: NSURL(string: "https://YOUR_AUTH0_DOMAIN/oauth/revoke")!,
                                        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()

Where:

  • client_id: Your application's Client ID.
  • client_secret (optional): Your application's Client Secret. Only required for confidential clients.
  • token: The refresh token you want to revoke.

The client should match the one the refresh token was issued for.

Revoke a token without the Client Secret

For clients that cannot keep the client_secret safe (for example, mobile apps), the /oauth/revoke endpoint supports passing no client_secret but the client itself must have the property tokenEndpointAuthMethod set to none, so the client can perform the following request:

{
"token" : YOUR_REFRESH_TOKEN,
"client_id" : YOUR_CLIENT_ID
}

If the request is valid, the refresh token is revoked and the response is HTTP 200, with an empty response body. Otherwise, the response body contains the error code and description.

{
  "error": "invalid_request|invalid_client",
  "error_description": "Description of the error"
}

The possible responses are:

HTTP Status Description
200 The refresh token is revoked, does not exist, or was not issued to the client making the revocation request. The response body is empty.
400 The required parameters were not sent in the request ("error": "invalid_request").
401 The request is not authorized ("error": "invalid_client"). Check that the client credentials (client_id and client_secret) are present in the request and hold valid values.

Use the Dashboard

When you revoke a refresh token using the dashboard, you have to revoke the user's authorized access to the application that issued the token. This renders the refresh token useless.

To do so, go to the Users section of the dashboard. Click the name of the user to view their Details page.

Select the Authorized Applications tab. This page lists all the clients to which the user has authorized access. Revoking an authorized application revokes also its associated refresh tokens.

To revoke the user's access to an authorized application, and hence invalidate the refresh token, click Revoke.

Revoke a refresh token using the dashboard

Rules

Rules will run for the Refresh Token Exchange. To execute special logic, you can look at the context.protocol property in your rule. If the value is oauth2-refresh-token, then this is the indication that the rule is running during the Refresh Token Exchange.

If you try to do a redirect with context.redirect, the authentication flow will return an error.

SDK Support

Web Apps

All our main SDKs support refresh tokens out of the box. Some are Node.js, ASP.NET Core, PHP, Java, and many more. For a complete listing refer to our Quickstarts page.

Single Page Apps

For web apps that execute on the browser, the way to refresh a token is using Silent Authentication. Auth0.js, our client-side library, provides methods for this out of the box.

  • The authorize method, redirects the user to the /authorize endpoint, in order to login and provide consent.
  • The parseHash method, parses a URL hash fragment to extract the result of an Auth0 authentication response.
  • The renewAuth method, attempts to get a new token from Auth0, using silent authentication. For more details refer to Using renewAuth to Acquire New Tokens.

More information on the library:

Mobile / Native Apps

For more information on using refresh tokens with our mobile SDKs refer to:

Keep reading