Set up a Client Credentials Grant using the Management API

Heads up! As part of our efforts to improve security and standards-based interoperability, we have implemented several new features in our authentication flows and made changes to existing ones. For an overview of these changes, and details on how you adopt them, refer to Introducing OIDC Conformant Authentication.

If you do not want to use the Auth0 Dashboard to create a Resource Server or you need to create one programmatically, you can use our Management API v2.

You will need the following:

  • A Management APIv2 token with the appropriate scopes. For details on how to get one refer to The Auth0 Management APIv2 Token.
  • The Client information (Client_Id and Client_Secret) for the Non Interactive Client that should already be created and visible in your Auth0 dashboard.

1. Create your Resource Server

Let's start by creating the Resource Server. This is the entity that represents the API that you want to issue access tokens for, identified by a friendly name and a URN identifier.

The following restrictions apply to the identifier:

  • It must be a valid URN.
  • It cannot be modified after creation.
  • It must be unique throughout your tenant.

We recommend using your public API endpoint as an identifier.

To create a Resource Server send a POST request to the /resource-servers endpoint of the Management APIv2 with an access_token that has the resource server scope (scope:resource_server).

The following example uses "My Sample API" as the name and "https://my-api-uri" as the identifier.


curl --request POST \
  --url 'https://YOUR_AUTH0_DOMAIN/api/v2/resource-servers' \
  --header 'authorization: Bearer Auth0_MGMT_API_ACCESS_TOKEN' \
  --header 'content-type: application/json' \
  --data '{"name":"My Sample API","identifier": "https://my-api-urn","signing_alg": "RS256","scopes": [{ "value": "sample-scope", "description": "Description for Sample Scope"}]}'
var client = new RestClient("https://YOUR_AUTH0_DOMAIN/api/v2/resource-servers");
var request = new RestRequest(Method.POST);
request.AddHeader("authorization", "Bearer Auth0_MGMT_API_ACCESS_TOKEN");
request.AddHeader("content-type", "application/json");
request.AddParameter("application/json", "{\"name\":\"My Sample API\",\"identifier\": \"https://my-api-urn\",\"signing_alg\": \"RS256\",\"scopes\": [{ \"value\": \"sample-scope\", \"description\": \"Description for Sample Scope\"}]}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
package main

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

func main() {

	url := "https://YOUR_AUTH0_DOMAIN/api/v2/resource-servers"

	payload := strings.NewReader("{\"name\":\"My Sample API\",\"identifier\": \"https://my-api-urn\",\"signing_alg\": \"RS256\",\"scopes\": [{ \"value\": \"sample-scope\", \"description\": \"Description for Sample Scope\"}]}")

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

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

	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/api/v2/resource-servers")
  .header("content-type", "application/json")
  .header("authorization", "Bearer Auth0_MGMT_API_ACCESS_TOKEN")
  .body("{\"name\":\"My Sample API\",\"identifier\": \"https://my-api-urn\",\"signing_alg\": \"RS256\",\"scopes\": [{ \"value\": \"sample-scope\", \"description\": \"Description for Sample Scope\"}]}")
  .asString();
var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://YOUR_AUTH0_DOMAIN/api/v2/resource-servers",
  "method": "POST",
  "headers": {
    "content-type": "application/json",
    "authorization": "Bearer Auth0_MGMT_API_ACCESS_TOKEN"
  },
  "processData": false,
  "data": "{\"name\":\"My Sample API\",\"identifier\": \"https://my-api-urn\",\"signing_alg\": \"RS256\",\"scopes\": [{ \"value\": \"sample-scope\", \"description\": \"Description for Sample Scope\"}]}"
}

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

var options = { method: 'POST',
  url: 'https://YOUR_AUTH0_DOMAIN/api/v2/resource-servers',
  headers: 
   { authorization: 'Bearer Auth0_MGMT_API_ACCESS_TOKEN',
     'content-type': 'application/json' },
  body: 
   { name: 'My Sample API',
     identifier: 'https://my-api-urn',
     signing_alg: 'RS256',
     scopes: 
      [ { value: 'sample-scope',
          description: 'Description for Sample Scope' } ] },
  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",
                           @"authorization": @"Bearer Auth0_MGMT_API_ACCESS_TOKEN" };
NSDictionary *parameters = @{ @"name": @"My Sample API",
                              @"identifier": @"https://my-api-urn",
                              @"signing_alg": @"RS256",
                              @"scopes": @[ @{ @"value": @"sample-scope", @"description": @"Description for Sample Scope" } ] };

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

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://YOUR_AUTH0_DOMAIN/api/v2/resource-servers"]
                                                       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/api/v2/resource-servers",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "{\"name\":\"My Sample API\",\"identifier\": \"https://my-api-urn\",\"signing_alg\": \"RS256\",\"scopes\": [{ \"value\": \"sample-scope\", \"description\": \"Description for Sample Scope\"}]}",
  CURLOPT_HTTPHEADER => array(
    "authorization: Bearer Auth0_MGMT_API_ACCESS_TOKEN",
    "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 = "{\"name\":\"My Sample API\",\"identifier\": \"https://my-api-urn\",\"signing_alg\": \"RS256\",\"scopes\": [{ \"value\": \"sample-scope\", \"description\": \"Description for Sample Scope\"}]}"

headers = {
    'content-type': "application/json",
    'authorization': "Bearer Auth0_MGMT_API_ACCESS_TOKEN"
    }

conn.request("POST", "/YOUR_AUTH0_DOMAIN/api/v2/resource-servers", payload, headers)

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

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

url = URI("https://YOUR_AUTH0_DOMAIN/api/v2/resource-servers")

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["authorization"] = 'Bearer Auth0_MGMT_API_ACCESS_TOKEN'
request.body = "{\"name\":\"My Sample API\",\"identifier\": \"https://my-api-urn\",\"signing_alg\": \"RS256\",\"scopes\": [{ \"value\": \"sample-scope\", \"description\": \"Description for Sample Scope\"}]}"

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

let headers = [
  "content-type": "application/json",
  "authorization": "Bearer Auth0_MGMT_API_ACCESS_TOKEN"
]
let parameters = [
  "name": "My Sample API",
  "identifier": "https://my-api-urn",
  "signing_alg": "RS256",
  "scopes": [
    [
      "value": "sample-scope",
      "description": "Description for Sample Scope"
    ]
  ]
]

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

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

You can include multiple scopes. This array represents the universe of scopes your API will support. You can modify this later by issuing a PATCH operation.

Sample response:

{
    "id": "56f0131ffdf1c311694f4cc7",
    "name": "My Sample API",
    "identifier": "https://my-api-urn",
    "scopes": [
        {
            "value": "sample-scope",
            "description": "Description for Sample Scope"
        }
    ],
    "signing_alg": "RS256",
    "signing_secret": "FF1prn9UxZotnolsDVwEJhqqyRmwdSu5",
    "token_lifetime": 86400
}

Note the following:

  • The identifier value (https://my-api-urn) will be used from now on as the audience for any OAuth 2.0 grant, that wants to access this API.
  • The algorithm that your API will use to sign tokens will be the RS256 (signing_alg).
  • The secret used to sign the tokens will be FF1prn9UxZotnolsDVwEJhqqyRmwdSu5 (signing_secret).
  • The generated tokens will expire after 86400 seconds (token_lifetime).

2. Authorize the Client

Now that the API and the Client are defined in Auth0, you can create a trust relationship between them. To do so, authorize the Client to access the API, while defining the scopes that should be given to the Client (meaning the actions the Client will be able to perform on the API).

To authorize your Client send a POST request to the /client-grants endpoint of the Management APIv2 with an access_token that has the create client grants scope (create:client_grantss).

The following example authorizes the Client with Id YOUR_CLIENT_ID, to access the API with Identifier https://my-api-urn, while granting the scope sample-scope.


curl --request POST \
  --url 'https://YOUR_AUTH0_DOMAIN/api/v2/client-grants' \
  --header 'authorization: Bearer Auth0_MGMT_API_ACCESS_TOKEN' \
  --header 'content-type: application/json' \
  --data '{"client_id": "YOUR_CLIENT_ID","audience": "https://my-api-urn","scope":["sample-scope"]}'
var client = new RestClient("https://YOUR_AUTH0_DOMAIN/api/v2/client-grants");
var request = new RestRequest(Method.POST);
request.AddHeader("authorization", "Bearer Auth0_MGMT_API_ACCESS_TOKEN");
request.AddHeader("content-type", "application/json");
request.AddParameter("application/json", "{\"client_id\": \"YOUR_CLIENT_ID\",\"audience\": \"https://my-api-urn\",\"scope\":[\"sample-scope\"]}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
package main

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

func main() {

	url := "https://YOUR_AUTH0_DOMAIN/api/v2/client-grants"

	payload := strings.NewReader("{\"client_id\": \"YOUR_CLIENT_ID\",\"audience\": \"https://my-api-urn\",\"scope\":[\"sample-scope\"]}")

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

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

	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/api/v2/client-grants")
  .header("content-type", "application/json")
  .header("authorization", "Bearer Auth0_MGMT_API_ACCESS_TOKEN")
  .body("{\"client_id\": \"YOUR_CLIENT_ID\",\"audience\": \"https://my-api-urn\",\"scope\":[\"sample-scope\"]}")
  .asString();
var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://YOUR_AUTH0_DOMAIN/api/v2/client-grants",
  "method": "POST",
  "headers": {
    "content-type": "application/json",
    "authorization": "Bearer Auth0_MGMT_API_ACCESS_TOKEN"
  },
  "processData": false,
  "data": "{\"client_id\": \"YOUR_CLIENT_ID\",\"audience\": \"https://my-api-urn\",\"scope\":[\"sample-scope\"]}"
}

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

var options = { method: 'POST',
  url: 'https://YOUR_AUTH0_DOMAIN/api/v2/client-grants',
  headers: 
   { authorization: 'Bearer Auth0_MGMT_API_ACCESS_TOKEN',
     'content-type': 'application/json' },
  body: 
   { client_id: 'YOUR_CLIENT_ID',
     audience: 'https://my-api-urn',
     scope: [ 'sample-scope' ] },
  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",
                           @"authorization": @"Bearer Auth0_MGMT_API_ACCESS_TOKEN" };
NSDictionary *parameters = @{ @"client_id": @"YOUR_CLIENT_ID",
                              @"audience": @"https://my-api-urn",
                              @"scope": @[ @"sample-scope" ] };

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

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://YOUR_AUTH0_DOMAIN/api/v2/client-grants"]
                                                       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/api/v2/client-grants",
  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\",\"audience\": \"https://my-api-urn\",\"scope\":[\"sample-scope\"]}",
  CURLOPT_HTTPHEADER => array(
    "authorization: Bearer Auth0_MGMT_API_ACCESS_TOKEN",
    "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\",\"audience\": \"https://my-api-urn\",\"scope\":[\"sample-scope\"]}"

headers = {
    'content-type': "application/json",
    'authorization': "Bearer Auth0_MGMT_API_ACCESS_TOKEN"
    }

conn.request("POST", "/YOUR_AUTH0_DOMAIN/api/v2/client-grants", payload, headers)

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

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

url = URI("https://YOUR_AUTH0_DOMAIN/api/v2/client-grants")

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["authorization"] = 'Bearer Auth0_MGMT_API_ACCESS_TOKEN'
request.body = "{\"client_id\": \"YOUR_CLIENT_ID\",\"audience\": \"https://my-api-urn\",\"scope\":[\"sample-scope\"]}"

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

let headers = [
  "content-type": "application/json",
  "authorization": "Bearer Auth0_MGMT_API_ACCESS_TOKEN"
]
let parameters = [
  "client_id": "YOUR_CLIENT_ID",
  "audience": "https://my-api-urn",
  "scope": ["sample-scope"]
]

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

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

Sample response:

{
    "id": "cgr_JGa6ZckLjnt60rWe",
    "client_id": "YOUR_CLIENT_ID",
    "audience": "https://test-api",
    "scope": [
        "sample-scope"
    ]
}

3. That's it!

Now that all the elements are in place, you can request access tokens for your API from Auth0.

For details on how to do so, refer to Execute a Client Credentials Grant.