Execute an Authorization Code Grant Flow about:reader?url=https://auth0.com/docs/api-auth...
auth0.com
Execute an Authorization Code Grant
Flow
Auth0
16-21 minutes
The Authorization Code is an OAuth 2.0 grant that regular web
apps use in order to access an API. In this document we will work
through the steps needed in order to implement this: get the user's
authorization, get a token and access the API using the token.
Before beginning this tutorial, please:
Check that your Application's Grant Type property is set
appropriately
Register the API with Auth0
To begin an Authorization Code flow, your web application should
first send the user to the authorization URL:
https://YOUR_DOMAIN/authorize?
audience=YOUR_API_AUDIENCE&
scope=YOUR_SCOPE&
response_type=code&
client_id=YOUR_CLIENT_ID&
redirect_uri=https://YOUR_APP/callback&
state=YOUR_OPAQUE_VALUE
Where:
audience: The unique identifier of the API the web app wants to
access. Use the Identifier value on the Settings tab for the API you
created as part of the prerequisites for this tutorial.
1 of 18 7/23/20, 10:54 AM
Execute an Authorization Code Grant Flow about:reader?url=https://auth0.com/docs/api-auth...
scope: The scopes which you want to request authorization for.
These must be separated by a space. You can request any of the
standard OpenID Connect (OIDC) scopes about users, such as
profile and email, custom claims that must conform to a
namespaced format, or any scopes supported by the target API (for
example, read:contacts). Include offline_access to get a
Refresh Token (make sure that the Allow Offline Access field is
enabled in the API Settings).
response_type: Denotes the kind of credential that Auth0 will
return (code vs token). For this flow, the value must be code.
client_id: Your application's Client ID. You can find this value at
your Application's Settings.
state: An opaque value the application adds to the initial request
that Auth0 includes when redirecting back to the application. This
value must be used by the application to prevent CSRF attacks. For
more information, see State Parameter.
redirect_uri: The URL to which Auth0 will redirect the browser
after authorization has been granted by the user. The Authorization
Code will be available in the code URL parameter. This URL must
be specified as a valid callback URL under your Application's
Settings.
For example:
<a href="https://YOUR_DOMAIN
/authorize?scope=appointments%20contacts&
audience=appointments:api&response_type=code&
client_id=YOUR_CLIENT_ID&redirect_uri=https:
//YOUR_APP/callback">
Sign In
</a>
The purpose of this call is to obtain consent from the user to invoke
the API (specified in audience) to do certain things (specified in
2 of 18 7/23/20, 10:54 AM
Execute an Authorization Code Grant Flow about:reader?url=https://auth0.com/docs/api-auth...
scope) on behalf of the user. Auth0 will authenticate the user and
obtain consent, unless consent has been previously given.
Note that if you alter the value in scope, Auth0 will require consent
to be given again.
Now that you have an Authorization Code, you must exchange it for
an Access Token that can be used to call your API. Using the
Authorization Code (code) from the previous step, you will need to
POST to the Token URL:
curl --request POST \
--url 'https://YOUR_DOMAIN/oauth/token' \
--header 'content-type: application/x-www-form-
urlencoded' \
--data grant_type=authorization_code \
--data 'client_id=YOUR_CLIENT_ID' \
--data client_secret=YOUR_CLIENT_SECRET \
--data code=YOUR_AUTHORIZATION_CODE \
--data 'redirect_uri=https://YOUR_APP/callback'
var client = new RestClient("https://YOUR_DOMAIN
/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-
www-form-urlencoded");
request.AddParameter("application/x-www-form-
urlencoded", "grant_type=authorization_code&
client_id=%24%7Baccount.clientId%7D&
client_secret=YOUR_CLIENT_SECRET&
code=YOUR_AUTHORIZATION_CODE&redirect_uri=
%24%7Baccount.callback%7D",
ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
package main
3 of 18 7/23/20, 10:54 AM
Execute an Authorization Code Grant Flow about:reader?url=https://auth0.com/docs/api-auth...
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://YOUR_DOMAIN/oauth/token"
payload :=
strings.NewReader("grant_type=authorization_code&
client_id=%24%7Baccount.clientId%7D&
client_secret=YOUR_CLIENT_SECRET&
code=YOUR_AUTHORIZATION_CODE&redirect_uri=
%24%7Baccount.callback%7D")
req, _ := http.NewRequest("POST", url,
payload)
req.Header.Add("content-type",
"application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
4 of 18 7/23/20, 10:54 AM
Execute an Authorization Code Grant Flow about:reader?url=https://auth0.com/docs/api-auth...
HttpResponse<String> response =
Unirest.post("https://YOUR_DOMAIN/oauth/token")
.header("content-type", "application/x-www-
form-urlencoded")
.body("grant_type=authorization_code&client_id=
%24%7Baccount.clientId%7D&
client_secret=YOUR_CLIENT_SECRET&
code=YOUR_AUTHORIZATION_CODE&redirect_uri=
%24%7Baccount.callback%7D")
.asString();
var request = require("request");
var options = {
method: 'POST',
url: 'https://YOUR_DOMAIN/oauth/token',
headers: {'content-type': 'application/x-www-
form-urlencoded'},
form: {
grant_type: 'authorization_code',
client_id: 'YOUR_CLIENT_ID',
client_secret: 'YOUR_CLIENT_SECRET',
code: 'YOUR_AUTHORIZATION_CODE',
redirect_uri: 'https://YOUR_APP/callback'
}
};
request(options, function (error, response, body)
{
if (error) throw new Error(error);
console.log(body);
});
#import <Foundation/Foundation.h>
5 of 18 7/23/20, 10:54 AM
Execute an Authorization Code Grant Flow about:reader?url=https://auth0.com/docs/api-auth...
NSDictionary *headers = @{ @"content-type":
@"application/x-www-form-urlencoded" };
NSMutableData *postData = [[NSMutableData alloc]
initWithData:[@"grant_type=authorization_code"
dataUsingEncoding:NSUTF8StringEncoding]];
[postData appendData:
[@"&client_id=YOUR_CLIENT_ID"
dataUsingEncoding:NSUTF8StringEncoding]];
[postData appendData:
[@"&client_secret=YOUR_CLIENT_SECRET"
dataUsingEncoding:NSUTF8StringEncoding]];
[postData appendData:
[@"&code=YOUR_AUTHORIZATION_CODE"
dataUsingEncoding:NSUTF8StringEncoding]];
[postData appendData:
[@"&redirect_uri=https://YOUR_APP/callback"
dataUsingEncoding:NSUTF8StringEncoding]];
NSMutableURLRequest *request =
[NSMutableURLRequest requestWithURL:[NSURL
URLWithString:@"https://YOUR_DOMAIN/oauth/token"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];
NSURLSession *session = [NSURLSession
sharedSession];
6 of 18 7/23/20, 10:54 AM
Execute an Authorization Code Grant Flow about:reader?url=https://auth0.com/docs/api-auth...
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_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=
%24%7Baccount.clientId%7D&
7 of 18 7/23/20, 10:54 AM
Execute an Authorization Code Grant Flow about:reader?url=https://auth0.com/docs/api-auth...
client_secret=YOUR_CLIENT_SECRET&
code=YOUR_AUTHORIZATION_CODE&redirect_uri=
%24%7Baccount.callback%7D",
CURLOPT_HTTPHEADER => array(
"content-type: application/x-www-form-
urlencoded"
),
));
$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=%24%7Baccount.clientId%7D&
client_secret=YOUR_CLIENT_SECRET&
code=YOUR_AUTHORIZATION_CODE&redirect_uri=
%24%7Baccount.callback%7D"
headers = { 'content-type': "application/x-www-
form-urlencoded" }
conn.request("POST", "/YOUR_DOMAIN/oauth/token",
8 of 18 7/23/20, 10:54 AM
Execute an Authorization Code Grant Flow about:reader?url=https://auth0.com/docs/api-auth...
payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://YOUR_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/x-www-
form-urlencoded'
request.body = "grant_type=authorization_code&
client_id=%24%7Baccount.clientId%7D&
client_secret=YOUR_CLIENT_SECRET&
code=YOUR_AUTHORIZATION_CODE&redirect_uri=
%24%7Baccount.callback%7D"
response = http.request(request)
puts response.read_body
import Foundation
let headers = ["content-type": "application/x-
www-form-urlencoded"]
let postData = NSMutableData(data:
9 of 18 7/23/20, 10:54 AM
Execute an Authorization Code Grant Flow about:reader?url=https://auth0.com/docs/api-auth...
"grant_type=authorization_code".data(using:
String.Encoding.utf8)!)
postData.append("&client_id=YOUR_CLIENT_ID".data(using:
String.Encoding.utf8)!)
postData.append("&client_secret=YOUR_CLIENT_SECRET".data(using:
String.Encoding.utf8)!)
postData.append("&code=YOUR_AUTHORIZATION_CODE".data(using:
String.Encoding.utf8)!)
postData.append("&redirect_uri=https://YOUR_APP
/callback".data(using: String.Encoding.utf8)!)
let request = NSMutableURLRequest(url:
NSURL(string: "https://YOUR_DOMAIN/oauth/token")!
as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data
let session = URLSession.shared
let dataTask = session.dataTask(with: request as
URLRequest, completionHandler: { (data, response,
error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as?
HTTPURLResponse
print(httpResponse)
}
10 of 18 7/23/20, 10:54 AM
Execute an Authorization Code Grant Flow about:reader?url=https://auth0.com/docs/api-auth...
})
dataTask.resume()
Where:
grant_type: This must be authorization_code.
client_id: Your application's Client ID.
client_secret: Your application's Client Secret.
code: The Authorization Code received from the initial authorize
call.
redirect_uri: The URL must match exactly the redirect_uri
passed to /authorize.
The response contains the access_token, refresh_token,
id_token, and token_type values, for example:
{
"access_token": "eyJz93a...k4laUWw",
"refresh_token": "GEbRxBN...edjnXbL",
"id_token": "eyJ0XAi...4faeEoQ",
"token_type": "Bearer"
}
Note that refresh_token will only be present in the response if
you included the offline_access scope AND enabled Allow
Offline Access for your API in the Dashboard. See Refresh Tokens
for more information.
Security Warning
It is important to understand that the Authorization Code flow
should only be used in cases such as a Regular Web Application
where the Client Secret can be safely stored. In cases such as a
Single-Page Application, the Client Secret is available to the
application (in the web browser), so the integrity of the Client Secret
11 of 18 7/23/20, 10:54 AM
Execute an Authorization Code Grant Flow about:reader?url=https://auth0.com/docs/api-auth...
cannot be maintained. That is why the Authorization Code Flow
with PKCE is more appropriate in that case.
Once the Access Token has been obtained it can be used to make
calls to the API by passing it as a Bearer Token in the
Authorization header of the HTTP request:
curl --request GET \
--url https://someapi.com/api \
--header 'authorization: Bearer ACCESS_TOKEN' \
--header 'content-type: application/json'
var client = new RestClient("https://someapi.com
/api");
var request = new RestRequest(Method.GET);
request.AddHeader("content-type",
"application/json");
request.AddHeader("authorization", "Bearer
ACCESS_TOKEN");
IRestResponse response = client.Execute(request);
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main() {
url := "https://someapi.com/api"
req, _ := http.NewRequest("GET", url,
nil)
12 of 18 7/23/20, 10:54 AM
Execute an Authorization Code Grant Flow about:reader?url=https://auth0.com/docs/api-auth...
req.Header.Add("content-type",
"application/json")
req.Header.Add("authorization", "Bearer
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.get("https://someapi.com/api")
.header("content-type", "application/json")
.header("authorization", "Bearer ACCESS_TOKEN")
.asString();
var request = require("request");
var options = {
method: 'GET',
url: 'https://someapi.com/api',
headers: {'content-type': 'application/json',
authorization: 'Bearer ACCESS_TOKEN'}
};
request(options, function (error, response, body)
{
if (error) throw new Error(error);
console.log(body);
13 of 18 7/23/20, 10:54 AM
Execute an Authorization Code Grant Flow about:reader?url=https://auth0.com/docs/api-auth...
});
#import <Foundation/Foundation.h>
NSDictionary *headers = @{ @"content-type":
@"application/json",
@"authorization":
@"Bearer ACCESS_TOKEN" };
NSMutableURLRequest *request =
[NSMutableURLRequest requestWithURL:[NSURL
URLWithString:@"https://someapi.com/api"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:@"GET"];
[request setAllHTTPHeaderFields:headers];
NSURLSession *session = [NSURLSession
sharedSession];
NSURLSessionDataTask *dataTask = [session
dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse
*response, NSError *error) {
if (error) {
NSLog(@"%@", error);
}
else {
NSHTTPURLResponse *httpResponse =
14 of 18 7/23/20, 10:54 AM
Execute an Authorization Code Grant Flow about:reader?url=https://auth0.com/docs/api-auth...
(NSHTTPURLResponse *) response;
NSLog(@"%@", httpResponse);
}
}];
[dataTask resume];
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://someapi.com/api",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => array(
"authorization: Bearer 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
15 of 18 7/23/20, 10:54 AM
Execute an Authorization Code Grant Flow about:reader?url=https://auth0.com/docs/api-auth...
conn = http.client.HTTPSConnection("someapi.com")
headers = {
'content-type': "application/json",
'authorization': "Bearer ACCESS_TOKEN"
}
conn.request("GET", "/api", headers=headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://someapi.com/api")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(url)
request["content-type"] = 'application/json'
request["authorization"] = 'Bearer ACCESS_TOKEN'
response = http.request(request)
puts response.read_body
import Foundation
let headers = [
16 of 18 7/23/20, 10:54 AM
Execute an Authorization Code Grant Flow about:reader?url=https://auth0.com/docs/api-auth...
"content-type": "application/json",
"authorization": "Bearer ACCESS_TOKEN"
]
let request = NSMutableURLRequest(url:
NSURL(string: "https://someapi.com/api")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as
URLRequest, completionHandler: { (data, response,
error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as?
HTTPURLResponse
print(httpResponse)
}
})
dataTask.resume()
Once your API receives a request with a Bearer Access Token, the
first thing to do is to validate the token. This consists of a series of
steps, and if any of these fails then the request must be rejected.
For details on the validations that should be performed, see
Validate Access Tokens.
17 of 18 7/23/20, 10:54 AM
Execute an Authorization Code Grant Flow about:reader?url=https://auth0.com/docs/api-auth...
You can use Rules to change the returned scopes of the Access
Token and/or add claims to it (and the ID Token) with a script like
this:
function(user, context, callback) {
context.accessToken['http://foo/bar'] =
'value';
context.idToken['http://fiz/baz'] = 'some other
value';
context.accessToken.scope = ['array', 'of',
'strings'];
callback(null, user, context);
}
If you wish to execute special logic unique to the Authorization
Code grant, you can look at the context.protocol property in
your rule. If the value is oidc-basic-profile, then the rule is
running during the Authorization Code grant.
Refresh Tokens
How to configure an API in Auth0
Application Authentication for Server-side Web Apps
Tokens
18 of 18 7/23/20, 10:54 AM