API Scopes

Versioncurrent

API scopes allow you to define the API data accessible to your applications.

Background

When you create an API in Auth0, you can use scopes to control how and what someone can access. For example, if you want users to be able to read and delete contact information, you would create the follow two scopes to reflect these two actions:

  • read:contacts
  • delete:contacts

If you wanted to expand our example on asking for standard claims to include also the read:contacts permission, then you would using something like the following sample URL to initiate the authentication flow using the Implicit grant:

https://YOUR_AUTH0_DOMAIN/authorize?
  audience=YOUR_API_AUDIENCE&
  scope=openid%20profile%20email%20read:contacts&
  response_type=id_token%20token&
  client_id=YOUR_CLIENT_ID&
  redirect_uri=https://YOUR_APP/callback&
  nonce=YOUR_CRYPTOGRAPHIC_NONCE
  state=YOUR_OPAQUE_VALUE

Note the differences between the example above and the example on asking for standard claims. In the example above, we want to get an Access Token, that will allow us to access the API, with the rights to do specific actions. To do so, we changed two parameters and added a new one:

  • audience: New parameter added for this example. Its value is the unique identifier of the API we want to get access to.

  • scope: We appended the value read:contacts. This denotes the rights that we want to be granted at the API (in this case, read contact information).

  • response_type: We appended the value token. This tells the Authorization Server (Auth0 in our case) to issue an Access Token as well, not only an ID Token. The Access Token will be sent to the API as credentials.

Define scopes using the Dashboard

By default, any user of any application can ask for any scope defined here. You can implement access policies to limit this behavior via Rules.

You can define API scopes using the Dashboard. Select the API you want to edit, and open up its Scopes tab.

Provide the following parameters:

Parameter Description
Name The name of your scope
Description A friendly description for your scope

Click Add when you've provided the requested values.

API Scopes

Limiting API scopes being issued

An application can request any scope and the user will be prompted to approve those scopes during the authorization flow. This may not be a desirable situation, as you may want to limit the scopes based on, for example, the permissions (or role) of a user.

You can make use of the Authorization Extension in conjunction with a custom Rule to ensure that scopes are granted based on the permissions of a user.

This approach is discussed in more depth in some of our Architecture Scenarios. Specifically, you can review the entire Configure the Authorization Extension section of our SPA+API Architecture Scenario which demonstrates how to configure the Authorization Extension, and also create a custom Rule which will ensure scopes are granted based on the permissions of a user.

By default, the user consent page groups scopes for the same resource and displays all actions for that resource in a single line. For example, let's say you have an API defined with the following scopes:

  • read:messages: Be able to read your email messages
  • write:messages: Write messages

The consent page would display: Messages: read and write your messages.

However, you can set your tenant's use_scope_descriptions_for_consent flag to true to have the consent page display the Description field instead. This affects consent prompts for all APIs on the tenant.

With this flag enabled, the consent page would display: Be able to read your email messages, Write messages.

To set the use_scope_descriptions_for_consent flag, you will need to make the following call to the API:


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

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

	req.Header.Add("content-type", "application/json")
	req.Header.Add("authorization", "Bearer API_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 API_ACCESS_TOKEN")
  .header("cache-control", "no-cache")
  .body("{ \"flags\": { \"use_scope_descriptions_for_consent\": 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 API_ACCESS_TOKEN",
    "cache-control": "no-cache"
  },
  "processData": false,
  "data": "{ \"flags\": { \"use_scope_descriptions_for_consent\": 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 API_ACCESS_TOKEN',
     'content-type': 'application/json' },
  body: { flags: { use_scope_descriptions_for_consent: 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 API_ACCESS_TOKEN",
                           @"cache-control": @"no-cache" };
NSDictionary *parameters = @{ @"flags": @{ @"use_scope_descriptions_for_consent": @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\": { \"use_scope_descriptions_for_consent\": true } }",
  CURLOPT_HTTPHEADER => array(
    "authorization: Bearer API_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\": { \"use_scope_descriptions_for_consent\": true } }"

headers = {
    'content-type': "application/json",
    'authorization': "Bearer API_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 API_ACCESS_TOKEN'
request["cache-control"] = 'no-cache'
request.body = "{ \"flags\": { \"use_scope_descriptions_for_consent\": true } }"

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

let headers = [
  "content-type": "application/json",
  "authorization": "Bearer API_ACCESS_TOKEN",
  "cache-control": "no-cache"
]
let parameters = ["flags": ["use_scope_descriptions_for_consent": 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()