Using Rules with Client Credentials Grants

Caution: Preview Feature

This is a preview feature and may be changed prior to launch. You are advised to contact support before using this feature in a production application as future changes could be breaking.

You can now add rules into the client credentials exchange pipeline where you exchange a client_id and secret for an access_token.

Prior to Beginning Your Configuration

Please ensure that:

Creating the Rule

Note: You can only create one rule, which will then be executed for all clients and APIs.

1. Create the Rule For Use with Webtasks

Create a file named myrule.js, and enter the following:

module.exports = function(client, scope, audience, context, cb) {
  var access_token = {};
  access_token[''] = 'bar';
  access_token.scope = scope;
  cb(null, access_token);

This is a sample rule that will:

  • add an arbitrary claim ( to the access_token;
  • add an extra scope to the default scopes configured on your API.

2. Create the Webtask to Use Your Rule

Create the Webtask. You will need to set the following static metadata fields for the Webtask:

  • wt-compiler = auth0-ext-compilers/client-credentials-exchange
  • auth0-extension = runtime
  • auth0-extension-name = credentials-exchange
  • auth0-extension-secret = {random_secret}

The same {random_secret} value provided to the auth0-extension-secret metadata property must also be provided to the webtask code as an auth0-extension-secret secret parameter. This prevents unauthorized calls to this webtask. A secret may be conveniently created using openssl tool if your platform has it available:

SECRET=$(openssl rand 32 -base64) && \
wt create myrule.js \
  --meta wt-compiler=auth0-ext-compilers/client-credentials-exchange \
  --meta auth0-extension=runtime \
  --meta auth0-extension-name=credentials-exchange \
  --meta auth0-extension-secret=$SECRET \
  --secret auth0-extension-secret=$SECRET

3. Test Your Setup

To test your newly-created rule and webtask, make the following POST call:

curl --request POST \
  --url \
  --header 'content-type: application/json' \
  --data '{"client_id": "YOUR_CLIENT_ID","client_secret": "YOUR_CLIENT_SECRET","audience": "API_IDENTIFIER","grant_type": "client_credentials"}'
var client = new RestClient("");
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\",\"audience\": \"API_IDENTIFIER\",\"grant_type\": \"client_credentials\"}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
package main

import (

func main() {

	url := ""

	payload := strings.NewReader("{\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"audience\": \"API_IDENTIFIER\",\"grant_type\": \"client_credentials\"}")

	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)


HttpResponse<String> response ="")
  .header("content-type", "application/json")
  .body("{\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"audience\": \"API_IDENTIFIER\",\"grant_type\": \"client_credentials\"}")
var settings = {
  "async": true,
  "crossDomain": true,
  "url": "",
  "method": "POST",
  "headers": {
    "content-type": "application/json"
  "processData": false,
  "data": "{\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"audience\": \"API_IDENTIFIER\",\"grant_type\": \"client_credentials\"}"

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

var options = { method: 'POST',
  url: '',
  headers: { 'content-type': 'application/json' },
   { client_id: 'YOUR_CLIENT_ID',
     client_secret: 'YOUR_CLIENT_SECRET',
     audience: 'API_IDENTIFIER',
     grant_type: 'client_credentials' },
  json: true };

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

#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"content-type": @"application/json" };
NSDictionary *parameters = @{ @"client_id": @"YOUR_CLIENT_ID",
                              @"client_secret": @"YOUR_CLIENT_SECRET",
                              @"audience": @"API_IDENTIFIER",
                              @"grant_type": @"client_credentials" };

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

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@""]
[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 => "",
  CURLOPT_POSTFIELDS => "{\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"audience\": \"API_IDENTIFIER\",\"grant_type\": \"client_credentials\"}",
    "content-type: application/json"

$response = curl_exec($curl);
$err = curl_error($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\",\"audience\": \"API_IDENTIFIER\",\"grant_type\": \"client_credentials\"}"

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

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

res = conn.getresponse()
data =

require 'uri'
require 'net/http'

url = URI("")

http =, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request =
request["content-type"] = 'application/json'
request.body = "{\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"audience\": \"API_IDENTIFIER\",\"grant_type\": \"client_credentials\"}"

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",
  "audience": "API_IDENTIFIER",
  "grant_type": "client_credentials"

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

var request = NSMutableURLRequest(URL: NSURL(string: "")!,
                                        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) {
  } else {
    let httpResponse = response as? NSHTTPURLResponse


If all is well, you will receive a JWT access_token that looks like this:

  "iss": "",
  "sub": "YOUR_CLIENT_ID@clients",
  "aud": "API_IDENTIFIER",
  "exp": 1472832994,
  "iat": 1472746594,
  "scope": "test extra",
  "": "bar"

Implementation Notes

Input Parameters

The input parameters for the rule, including sample snippets:

  • client - object - the client asking for the token, including the client metadata (a key-value pair that can be set by client)

      "tenant":  "tenant_name",
      "id": "tenant_id",
      "name": "test_client",
      "metadata": {
        "some_metadata": "value"
  • scope - string array - the scopes available on the API that you have defined

  • audience - string - the API identifier available via the API settings page

  • context - object - the contextual information about the request

      "ip": "",
      "userAgent": "...",
      "webtask": {
        "secrets": { "FOO": "bar" }

Auth0 Runtime Expectation

The Auth0 Runtime expects you to return an access_token that looks like the following:

  "": "bar",
  "scope": [ "scope1", "scope2" ]

If you decide not to issue the token, you can return Error (cb(new Error('access denied'))).


You can use wt logs to see realtime logs. For additional information on reading the output, please consult Webtask Streaming Logs.