Call Your API Using the Single-Page Login Flow

This tutorial will help you call your own API using the single-page login flow. If you want to learn how the flow works and why you should use it, see Single-Page Login Flow. If you want to learn to add login to your single-page application (SPA), see Add Login Using the Single-Page Login Flow.

Auth0 makes it easy for your app to implement the single-page login flow using:

  • Auth0.js: The easiest way to implement the single-page login flow, which will do most of the heavy-lifting for you. Our Single-Page App Quickstarts will walk you through the process.
  • Authentication API: If you prefer to roll your own, keep reading to learn how to call our API directly.

Prerequisites

Before beginning this tutorial:

Steps

  1. Authorize the user: Request the user's authorization and redirect back to your app with the requested credentials.
  2. Call Your API: Use the retrieved Access Token to call your API.

Optional: Explore Sample Use Cases

Authorize the user

To begin the flow, you'll need to get the user's authorization. This step may include one or more of the following processes:

  • Authenticating the user;
  • Redirecting the user to an Identity Provider to handle authentication;
  • Checking for active SSO sessions;
  • Obtaining user consent for the requested permission level, unless consent has been previously given.

To authorize the user, your app must send the user to the authorization URL.

Example authorization URL

https://YOUR_AUTH0_DOMAIN/authorize?
    response_type=YOUR_RESPONSE_TYPE&
    client_id=YOUR_CLIENT_ID&
    redirect_uri=https://YOUR_APP/callback&
    scope=YOUR_SCOPE&
    audience=YOUR_API_AUDIENCE&
    state=STATE&
    nonce=NONCE

Parameters

Parameter Name Description
response_type Denotes the kind of credential that Auth0 will return (code or token). For the Implicit Flow, the value can be id_token, token, or id_token token. Specifically, id_token returns an ID Token, and token returns an Access Token.
client_id Your application's Client ID. You can find this value at your Application's Settings.
redirect_uri The URL to which Auth0 will redirect the browser after authorization has been granted by the user. You must specify this URL as a valid callback URL in your Application Settings.

Warning: Per the OAuth 2.0 Specification, Auth0 removes everything after the hash and does not honor any fragments.
scope Specifies the scopes for which you want to request authorization, which dictate which claims (or user attributes) you want returned. 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 conforming to a namespaced format, or any scopes supported by the target API (for example, read:contacts).
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.
state (recommended) An opaque arbitrary alphanumeric string that your app adds to the initial request and Auth0 includes when redirecting back to your application. To see how to use this value to prevent cross-site request forgery (CSRF) attacks, see Use the State Parameter Against CSRF Attacks.
nonce (required for response_type containing id_token token, otherwise recommended) A cryptographically random string that your app adds to the initial request and Auth0 includes inside the ID Token, used to prevent token replay attacks.

As an example, your HTML snippet for your authorization URL when adding login to your app might look like:

<a href="https://YOUR_AUTH0_DOMAIN/authorize?
  response_type=id_token token&
  client_id=YOUR_CLIENT_ID&
  redirect_uri=https://YOUR_APP/callback&
  scope=read:tests&
  audience=https://myapi.com&
  state=xyzABC123&
  nonce=eq...hPmz">
  Sign In
</a>

Response

If all goes well, you'll receive an HTTP 302 response. The requested credentials are included in a hash fragment at the end of the URL:

HTTP/1.1 302 Found
Location: https://YOUR_APP/callback#access_token=ey...MhPw&expires_in=7200&token_type=Bearer&id_token=ey...Fyqk&state=xyzABC123

Note that the returned values depend on what you requested as a response_type.

Response Type Components
id_token ID Token
token Access Token (plus expires_in and token_type values)
id_token token ID Token, Access Token (plus expires_in and token_type values)

Auth0 will also return any state value you included in your call to the authorization URL.

You should validate your tokens before saving them. To learn how, see Validate an ID Token and Verify Access Tokens.

ID Tokens contain user information that must be decoded and extracted.

Access Tokens are used to call the Auth0 Authentication API's /userinfo endpoint or another API. If you are calling your own API, the first thing your API will need to do is verify the Access Token.

Call your API

To call your API from a SPA, the application must pass the retrieved Access Token as a Bearer token in the Authorization header of your HTTP request.


curl --request GET \
  --url https://myapi.com/api \
  --header 'authorization: Bearer ACCESS_TOKEN' \
  --header 'content-type: application/json'
var client = new RestClient("https://myapi.com/api");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Bearer ACCESS_TOKEN");
request.AddHeader("content-type", "application/json");
IRestResponse response = client.Execute(request);
package main

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

func main() {

	url := "https://myapi.com/api"

	req, _ := http.NewRequest("GET", url, nil)

	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://myapi.com/api")
  .header("content-type", "application/json")
  .header("authorization", "Bearer ACCESS_TOKEN")
  .asString();
var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://myapi.com/api",
  "method": "GET",
  "headers": {
    "content-type": "application/json",
    "authorization": "Bearer ACCESS_TOKEN"
  }
}

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

var options = { method: 'GET',
  url: 'https://myapi.com/api',
  headers: 
   { authorization: 'Bearer ACCESS_TOKEN',
     'content-type': 'application/json' } };

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 ACCESS_TOKEN" };

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://myapi.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 = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://myapi.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

conn = http.client.HTTPSConnection("myapi.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'

url = URI("https://myapi.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 = [
  "content-type": "application/json",
  "authorization": "Bearer ACCESS_TOKEN"
]

var request = NSMutableURLRequest(URL: NSURL(string: "https://myapi.com/api")!,
                                        cachePolicy: .UseProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.HTTPMethod = "GET"
request.allHTTPHeaderFields = headers

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 Use Cases

Customize Tokens

You can use Rules to change the returned scopes of Access Tokens and/or add claims to Access and ID Tokens. To do so, add the following rule, which will run after the user authenticates:

function(user, context, callback) {

  // add custom claims to Access Token and ID Token
  context.accessToken['http://foo/bar'] = 'value';
  context.idToken['http://fiz/baz'] = 'some other value';

  // change scope
  context.accessToken.scope = ['array', 'of', 'strings'];

  callback(null, user, context);
}

Namespacing Custom Claims

Auth0 returns profile information in a structured claim format as defined by the OIDC specification. This means that custom claims added to ID Tokens or Access Tokens 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.

Keep Reading