Dynamic Client Registration

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.

Dynamic Client Registration is a feature, based on the OpenID Connect Dynamic Client Registration specification, that enables you to register clients dynamically. These clients are called third party clients (since they are registered and used by third party developers).

Third Party Client characteristics

Third party clients have the following characteristics:

How to get a Management APIv2 Token

In order to access the Management APIv2 endpoints from a third party client, you need a Management APIv2 Token. To get one you can use any of the API Authorization Flows, with the following request parameters:

  • audience=https://YOUR_AUTH0_DOMAIN/api/v2/
  • scope=read:current_user update:current_user_metadata

Enable dynamic registration

In this section we will see how you can enable the dynamic registration feature for your tenant.

By default, the feature is disabled for all tenants. To change this, you have to update some tenant settings, promote the connections you will use with your dynamic clients to domain connections, and update your client's login page (if you use Lock).

Auth0 supports Open Dynamic Registration, which means that if you enable this feature, anyone will be able to create clients in your tenant without a token.

Update tenant settings

In order to enable the feature, you need to set the enable_dynamic_client_registration flag to true in your tenant's settings.

You can update this flag using the Update tenant settings endpoint.


curl --request PATCH \
  --url 'https://YOUR_AUTH0_DOMAIN/api/v2/tenants/settings' \
  --header 'authorization: Bearer API2_ACCESS_TOKEN' \
  --header 'cache-control: no-cache' \
  --header 'content-type: application/json' \
  --data '{ "flags": { "enable_dynamic_client_registration": true } }'
var client = new RestClient("https://YOUR_AUTH0_DOMAIN/api/v2/tenants/settings");
var request = new RestRequest(Method.PATCH);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("authorization", "Bearer API2_ACCESS_TOKEN");
request.AddHeader("content-type", "application/json");
request.AddParameter("application/json", "{ \"flags\": { \"enable_dynamic_client_registration\": true } }", 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/tenants/settings"

	payload := strings.NewReader("{ \"flags\": { \"enable_dynamic_client_registration\": true } }")

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

	req.Header.Add("content-type", "application/json")
	req.Header.Add("authorization", "Bearer API2_ACCESS_TOKEN")
	req.Header.Add("cache-control", "no-cache")

	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.patch("https://YOUR_AUTH0_DOMAIN/api/v2/tenants/settings")
  .header("content-type", "application/json")
  .header("authorization", "Bearer API2_ACCESS_TOKEN")
  .header("cache-control", "no-cache")
  .body("{ \"flags\": { \"enable_dynamic_client_registration\": true } }")
  .asString();
var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://YOUR_AUTH0_DOMAIN/api/v2/tenants/settings",
  "method": "PATCH",
  "headers": {
    "content-type": "application/json",
    "authorization": "Bearer API2_ACCESS_TOKEN",
    "cache-control": "no-cache"
  },
  "processData": false,
  "data": "{ \"flags\": { \"enable_dynamic_client_registration\": true } }"
}

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

var options = { method: 'PATCH',
  url: 'https://YOUR_AUTH0_DOMAIN/api/v2/tenants/settings',
  headers: 
   { 'cache-control': 'no-cache',
     authorization: 'Bearer API2_ACCESS_TOKEN',
     'content-type': 'application/json' },
  body: { flags: { enable_dynamic_client_registration: true } },
  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 API2_ACCESS_TOKEN",
                           @"cache-control": @"no-cache" };
NSDictionary *parameters = @{ @"flags": @{ @"enable_dynamic_client_registration": @YES } };

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

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://YOUR_AUTH0_DOMAIN/api/v2/tenants/settings"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"PATCH"];
[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/tenants/settings",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "PATCH",
  CURLOPT_POSTFIELDS => "{ \"flags\": { \"enable_dynamic_client_registration\": true } }",
  CURLOPT_HTTPHEADER => array(
    "authorization: Bearer API2_ACCESS_TOKEN",
    "cache-control: no-cache",
    "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 = "{ \"flags\": { \"enable_dynamic_client_registration\": true } }"

headers = {
    'content-type': "application/json",
    'authorization': "Bearer API2_ACCESS_TOKEN",
    'cache-control': "no-cache"
    }

conn.request("PATCH", "/YOUR_AUTH0_DOMAIN/api/v2/tenants/settings", 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/tenants/settings")

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

request = Net::HTTP::Patch.new(url)
request["content-type"] = 'application/json'
request["authorization"] = 'Bearer API2_ACCESS_TOKEN'
request["cache-control"] = 'no-cache'
request.body = "{ \"flags\": { \"enable_dynamic_client_registration\": true } }"

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

let headers = [
  "content-type": "application/json",
  "authorization": "Bearer API2_ACCESS_TOKEN",
  "cache-control": "no-cache"
]
let parameters = ["flags": ["enable_dynamic_client_registration": true]]

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

var request = NSMutableURLRequest(URL: NSURL(string: "https://YOUR_AUTH0_DOMAIN/api/v2/tenants/settings")!,
                                        cachePolicy: .UseProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.HTTPMethod = "PATCH"
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 need to update the API2_ACCESS_TOKEN with a valid Auth0 API2 token with the scope update:tenant_settings. See How to get a Management APIv2 Token for details on how to do so.

Promote connections

Clients registered via the Dynamic Client Registration Endpoint are flagged as Third Party Clients and can only authenticate users using connections flagged as Domain Connections. These connections will be open for any dynamic client to allow users to authenticate.

You can promote a connection to domain level using the Update a Connection endpoint.


curl --request PATCH \
  --url 'https://YOUR_AUTH0_DOMAIN/api/v2/connections/CONNECTION_ID' \
  --header 'authorization: Bearer API2_ACCESS_TOKEN' \
  --header 'cache-control: no-cache' \
  --header 'content-type: application/json' \
  --data '{ "is_domain_connection": true }'
var client = new RestClient("https://YOUR_AUTH0_DOMAIN/api/v2/connections/CONNECTION_ID");
var request = new RestRequest(Method.PATCH);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("authorization", "Bearer API2_ACCESS_TOKEN");
request.AddHeader("content-type", "application/json");
request.AddParameter("application/json", "{ \"is_domain_connection\": true }", 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/connections/CONNECTION_ID"

	payload := strings.NewReader("{ \"is_domain_connection\": true }")

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

	req.Header.Add("content-type", "application/json")
	req.Header.Add("authorization", "Bearer API2_ACCESS_TOKEN")
	req.Header.Add("cache-control", "no-cache")

	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.patch("https://YOUR_AUTH0_DOMAIN/api/v2/connections/CONNECTION_ID")
  .header("content-type", "application/json")
  .header("authorization", "Bearer API2_ACCESS_TOKEN")
  .header("cache-control", "no-cache")
  .body("{ \"is_domain_connection\": true }")
  .asString();
var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://YOUR_AUTH0_DOMAIN/api/v2/connections/CONNECTION_ID",
  "method": "PATCH",
  "headers": {
    "content-type": "application/json",
    "authorization": "Bearer API2_ACCESS_TOKEN",
    "cache-control": "no-cache"
  },
  "processData": false,
  "data": "{ \"is_domain_connection\": true }"
}

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

var options = { method: 'PATCH',
  url: 'https://YOUR_AUTH0_DOMAIN/api/v2/connections/CONNECTION_ID',
  headers: 
   { 'cache-control': 'no-cache',
     authorization: 'Bearer API2_ACCESS_TOKEN',
     'content-type': 'application/json' },
  body: { is_domain_connection: true },
  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 API2_ACCESS_TOKEN",
                           @"cache-control": @"no-cache" };
NSDictionary *parameters = @{ @"is_domain_connection": @YES };

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

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://YOUR_AUTH0_DOMAIN/api/v2/connections/CONNECTION_ID"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"PATCH"];
[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/connections/CONNECTION_ID",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "PATCH",
  CURLOPT_POSTFIELDS => "{ \"is_domain_connection\": true }",
  CURLOPT_HTTPHEADER => array(
    "authorization: Bearer API2_ACCESS_TOKEN",
    "cache-control: no-cache",
    "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 = "{ \"is_domain_connection\": true }"

headers = {
    'content-type': "application/json",
    'authorization': "Bearer API2_ACCESS_TOKEN",
    'cache-control': "no-cache"
    }

conn.request("PATCH", "/YOUR_AUTH0_DOMAIN/api/v2/connections/CONNECTION_ID", 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/connections/CONNECTION_ID")

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

request = Net::HTTP::Patch.new(url)
request["content-type"] = 'application/json'
request["authorization"] = 'Bearer API2_ACCESS_TOKEN'
request["cache-control"] = 'no-cache'
request.body = "{ \"is_domain_connection\": true }"

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

let headers = [
  "content-type": "application/json",
  "authorization": "Bearer API2_ACCESS_TOKEN",
  "cache-control": "no-cache"
]
let parameters = ["is_domain_connection": true]

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

var request = NSMutableURLRequest(URL: NSURL(string: "https://YOUR_AUTH0_DOMAIN/api/v2/connections/CONNECTION_ID")!,
                                        cachePolicy: .UseProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.HTTPMethod = "PATCH"
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:

  • API2_ACCESS_TOKEN: Α valid Auth0 API2 token with the scope update:connections.
  • CONNECTION_ID: Τhe Id of the connection to be promoted.

Update the login page

If you use or would like to use an Auth0 Hosted Login Page with the Dynamic Client feature, you need to use at least version 10.7.x of Lock, and set __useTenantInfo: config.isThirdPartyClient when instantiating Lock.

Sample script:

<script src="https://cdn.auth0.com/js/lock/10.7/lock.min.js"></script>
...
<script>
  // Decode utf8 characters properly
  var config = JSON.parse(decodeURIComponent(escape(window.atob('@@config@@'))));

  var connection = config.connection;
  var prompt = config.prompt;
  var languageDictionary;
  var language;
  if (config.dict && config.dict.signin && config.dict.signin.title) {
    languageDictionary = { title: config.dict.signin.title };
  } else if (typeof config.dict === 'string') {
    language = config.dict;
  }

  var lock = new Auth0Lock(config.clientID, config.auth0Domain, {
    auth: {
      redirectUrl: config.callbackURL,
      responseType: config.callbackOnLocationHash ? 'token' : 'code',
      params: config.internalOptions
    },
    assetsUrl:  config.assetsUrl,
    allowedConnections: connection ? [connection] : null,
    rememberLastLogin: !prompt,
    language: language,
    languageDictionary: languageDictionary,
    closable: false,
    __useTenantInfo: config.isThirdPartyClient
  });

  lock.show();
</script>

Use dynamic registration

In this section we will see how a third party developer can register and configure a client.

Register your client

In order to dynamically register a client with Auth0, you need to send an HTTP POST message to the Client Registration endpoint: https://YOUR_AUTH0_DOMAIN/oidc/register. Note that Auth0 supports open Dynamic Registration, which means that the endpoint will accept a registration request without an OAuth 2.0 Access Tokens.

To create a client with the name My Example and the callback URLs https://client.example.com/callback and https://client.example.com/callback2, you would use the following.


curl --request POST \
  --url 'https://YOUR_AUTH0_DOMAIN/oidc/register' \
  --header 'content-type: application/json' \
  --data '{"client_name":"My Dynamic Client","redirect_uris": ["https://client.example.com/callback", "https://client.example.com/callback2"]}'
var client = new RestClient("https://YOUR_AUTH0_DOMAIN/oidc/register");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/json");
request.AddParameter("application/json", "{\"client_name\":\"My Dynamic Client\",\"redirect_uris\": [\"https://client.example.com/callback\", \"https://client.example.com/callback2\"]}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
package main

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

func main() {

	url := "https://YOUR_AUTH0_DOMAIN/oidc/register"

	payload := strings.NewReader("{\"client_name\":\"My Dynamic Client\",\"redirect_uris\": [\"https://client.example.com/callback\", \"https://client.example.com/callback2\"]}")

	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/oidc/register")
  .header("content-type", "application/json")
  .body("{\"client_name\":\"My Dynamic Client\",\"redirect_uris\": [\"https://client.example.com/callback\", \"https://client.example.com/callback2\"]}")
  .asString();
var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://YOUR_AUTH0_DOMAIN/oidc/register",
  "method": "POST",
  "headers": {
    "content-type": "application/json"
  },
  "processData": false,
  "data": "{\"client_name\":\"My Dynamic Client\",\"redirect_uris\": [\"https://client.example.com/callback\", \"https://client.example.com/callback2\"]}"
}

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

var options = { method: 'POST',
  url: 'https://YOUR_AUTH0_DOMAIN/oidc/register',
  headers: { 'content-type': 'application/json' },
  body: 
   { client_name: 'My Dynamic Client',
     redirect_uris: 
      [ 'https://client.example.com/callback',
        'https://client.example.com/callback2' ] },
  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_name": @"My Dynamic Client",
                              @"redirect_uris": @[ @"https://client.example.com/callback", @"https://client.example.com/callback2" ] };

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

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://YOUR_AUTH0_DOMAIN/oidc/register"]
                                                       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/oidc/register",
  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_name\":\"My Dynamic Client\",\"redirect_uris\": [\"https://client.example.com/callback\", \"https://client.example.com/callback2\"]}",
  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_name\":\"My Dynamic Client\",\"redirect_uris\": [\"https://client.example.com/callback\", \"https://client.example.com/callback2\"]}"

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

conn.request("POST", "/YOUR_AUTH0_DOMAIN/oidc/register", payload, headers)

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

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

url = URI("https://YOUR_AUTH0_DOMAIN/oidc/register")

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_name\":\"My Dynamic Client\",\"redirect_uris\": [\"https://client.example.com/callback\", \"https://client.example.com/callback2\"]}"

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

let headers = ["content-type": "application/json"]
let parameters = [
  "client_name": "My Dynamic Client",
  "redirect_uris": ["https://client.example.com/callback", "https://client.example.com/callback2"]
]

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

var request = NSMutableURLRequest(URL: NSURL(string: "https://YOUR_AUTH0_DOMAIN/oidc/register")!,
                                        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_name (required): The name of the Dynamic Client to be created.
  • redirect_uris (required): An array of URLs that Auth0 will deem valid to call at the end of an Authentication flow.

Optionally, you can set a value for token_endpoint_auth_method, which can be none or client_secret_post (default value).

The response includes the basic client information.

HTTP/1.1 201 Created
Content-Type: application/json
{
  "client_name": "My Dynamic Client",
  "client_id": "8SXWY6j3afl2CP5ntwEOpMdPxxy49Gt2",
  "client_secret": "Q5O...33P",
  "redirect_uris": [
    "https://client.example.com/callback",
    "https://client.example.com/callback2"
  ],
  "client_secret_expires_at": 0
}

Where:

  • client_id: Unique client identifier. This is the ID you will use while configuring your apps to use Auth0. It is generated by the system and it cannot be modified.
  • client_secret: Alphanumeric 64-bit client secret. This value is used by clients to authenticate to the token endpoint and for signing and validating ID tokens.
  • client_secret_expires_at: Time at which the client_secret will expire. For Auth0 this value will always be zero (0) which means that the client never expires.

Make a note of the client ID and secret, as these are the most important pieces for executing Authentication and Authorization Flows.

Also, keep in mind that Third Party Developers are not allowed to modify the client settings. In case this is necessary, they will need to contact the Tenant Owner with their request.

Configure your Client

Now that you have a client ID and secret, you can configure your application to authenticate users with Auth0.

We will go through a simple scenario, that showcases how to call an API from a client-side web app, using the Implicit Grant. For a list of tutorials on how to authenticate and authorize users, based on your application type, refer to API Authorization.

First, you need to configure your application to send the user to the authorization URL:

https://YOUR_AUTH0_DOMAIN/authorize?
  audience={API_AUDIENCE}&
  scope={SCOPE}&
  response_type={RESPONSE_TYPE}&
  client_id=YOUR_CLIENT_ID&
  redirect_uri=https://YOUR_APP/callback&
  nonce={CRYPTOGRAPHIC_NONCE}
  state={OPAQUE_VALUE}

Where:

  • audience (optional): The target API for which the Client Application is requesting access on behalf of the user. Set this parameter if you need API access.

  • scope (optional): The scopes which you want to request authorization for. These must be separated by a space. You can request any of the standard OIDC scopes about users, such as profile and email, custom claims that must conform to a namespaced format (see panel below for more info), or any scopes supported by the target API (for example, read:contacts). Set this parameter if you need API access.

    Custom claims namespaced format

    In order to improve compatibility for client applications, Auth0 will now return profile information in a structured claim format as defined by the OIDC specification. This means that in order to add custom claims to ID tokens or access tokens, they must conform to a namespaced format to avoid possible collisions with standard OIDC claims. For example, if you choose the namespace https://foo.com/ and you want to add a custom claim named myclaim, you would name the claim https://foo.com/myclaim, instead of myclaim.

  • response_type: The response type. For Implicit Grant you can either use token or id_token token. This will specify the type of token you will receive at the end of the flow. Use token to get only an access_token, or id_token token to get both an id_token and an access_token.

  • client_id: Your application's Client ID.

  • redirect_uri: The URL to which the Authorization Server (Auth0) will redirect the User Agent (Browser) after authorization has been granted by the User. The access_token (and optionally an id_token) will be available in the hash fragment of this URL. This URL must be specified as a valid callback URL under the Client Settings of your application.

  • state: An opaque value the clients adds to the initial request that the authorization server includes when redirecting the back to the client. This value must be used by the client to prevent CSRF attacks.

  • nonce: A string value which will be included in the ID token response from Auth0, used to prevent token replay attacks. It is required for response_type=id_token token.

For example:

<a href="https://YOUR_AUTH0_DOMAIN/authorize?scope=appointments%20contacts&audience=appointments:api&response_type=id_token%20token&client_id=YOUR_CLIENT_ID&redirect_uri=https://YOUR_APP/callback">
  Sign In
</a>

This call will redirect the user to Auth0, and upon successful authentication, back to your application (specifically to the redirect_uri).

If you need API access, then following the authentication, you need to extract the access token from the hash fragment of the URL, and use it to make calls to the API, by passing it as a Bearer token in the Authorization header of the HTTP request.