Authentication for Mobile & Desktop Apps

You can authenticate users of your mobile/desktop applications by:

  • Using Lock, a drop-in authentication widget that provides a standard set of behaviors and a customizable user interface;
  • Using one of the Auth0 SDKs, which are client-side libraries that do not include a user interface but allow for expanded customization of the authentication behavior and appearance of the login screen;
  • Calling the Auth0 Authentication API endpoints, which allows you to integrate with Auth0 without requiring the user of Auth0's libraries.

This article will cover how to call the Auth0 Authentication API endpoints using Proof Key for Code Exchange (PKCE) during the authentication process.

If you would like to implement this functionality using either Lock or one of the Auth0 SDKs, please refer to the following resources:

Overview

Auth0 exposes OAuth 2.0 endpoints that you can use to authenticate users. You can call these endpoints through an embedded browser in your native application. After authentication completes, you can return an ID Token that contains the user's profile information.

Instead of following this tutorial, you can use any of Auth0's client libraries. These encapsulate all the logic required and make it easier for your to implement authentication. Please refer to our Native Quickstarts to get started.

Register Your Client

If you haven't already created a new Client in Auth0, you'll need to do so before implementing your authentication flow. The Auth0 Client maps to your application and allows your application to use Auth0 for authentication purposes.

Go to the Auth0 Dashboard and click on Clients in the left-hand navigation bar. Click Create Client.

The Create Client window will open, allowing you to enter the name of your new Client. Choose Native as the Client Type. When done, click on Create to proceed.

The Authorization Code flow with PKCE can only be used for Native Clients.

Once Auth0 creates the Client, navigate to the Client's Settings tab to:

  • Add the following URL to the Allowed Callback URLs field: https://YOUR_AUTH0_DOMAIN/mobile;
  • Enable the OIDC Conformant Flag under the OAuth area of Advanced Settings.

Scroll to the bottom of the page and click Save.

Implement Authentication

For our mobile app, we will implement the OAuth 2.0 Authorization Code Grant Flow using Proof Key for Code Exchange.

Step 1: Create a Random Key and the Code Challenge

First, you will need to generate and store a code_verifier, which is a cryptographically random key that, along with its transformed value (called the code_challenge), will be sent to Auth0 for an authorization_code.

For sample scripts, to generate a code_verifier and a code_challenge, refer to Execute an Authorization Code Grant Flow with PKCE.

Step 2: Authorize the User

Once you've created the code_verifier and the code_challenge, you'll need to get the user's authorization. This is technically the beginning of the authorization flow, and 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.

To authorize the user, your application must send the user to the authorization URL (which includes the code_challenge you generated in the previous step, as well as the method you used to generate the code_challenge). Your URL should follow this format:

https://YOUR_AUTH0_DOMAIN/authorize?
    scope=SCOPE&
    response_type=code&
    client_id=YOUR_CLIENT_ID&
    code_challenge=CODE_CHALLENGE&
    code_challenge_method=S256&
    redirect_uri=YOUR_AUTH0_DOMAIN/mobile

Note that the sample Authorization URL doesn't include an audience parameter. In this scenario, your app needs to authenticate only the user, not access an API, so we omit audience.

For details on the request parameters, refer to Execute an Authorization Code Grant Flow with PKCE.

As an example, your HTML snippet for your authorization URL might look like the following:

<a href="https://YOUR_AUTH0_DOMAIN/authorize?
  scope=openid%20profile&
  response_type=code&
  client_id=YOUR_CLIENT_ID&
  code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&
  code_challenge_method=S256&
  redirect_uri=https://YOUR_AUTH0_DOMAIN/mobile">
  Sign In
</a>

If all goes well, you'll receive an HTTP 302 response:

HTTP/1.1 302 Found
Location: https://YOUR_AUTH0_DOMAIN/mobile?code=AUTHORIZATION_CODE

Note the authorization code included at the end of the included URL.

Step 3: Obtain an ID Token

Using the authorization code obtained in step 2, you can obtain the ID token by making the appropriate POST call to the tokens endpoint.


curl --request POST \
  --url 'https://YOUR_AUTH0_DOMAIN/oauth/token' \
  --header 'content-type: application/json' \
  --data '{"grant_type":"authorization_code","client_id": "YOUR_CLIENT_ID","code_verifier": "YOUR_GENERATED_CODE_VERIFIER","code": "YOUR_AUTHORIZATION_CODE","redirect_uri": "https://YOUR_AUTH0_DOMAIN/mobile", }'
var client = new RestClient("https://YOUR_AUTH0_DOMAIN/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/json");
request.AddParameter("application/json", "{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"https://YOUR_AUTH0_DOMAIN/mobile\", }", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
package main

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

func main() {

	url := "https://YOUR_AUTH0_DOMAIN/oauth/token"

	payload := strings.NewReader("{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"https://YOUR_AUTH0_DOMAIN/mobile\", }")

	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/oauth/token")
  .header("content-type", "application/json")
  .body("{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"https://YOUR_AUTH0_DOMAIN/mobile\", }")
  .asString();
var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://YOUR_AUTH0_DOMAIN/oauth/token",
  "method": "POST",
  "headers": {
    "content-type": "application/json"
  },
  "data": "{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"https://YOUR_AUTH0_DOMAIN/mobile\", }"
}

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

var options = { method: 'POST',
  url: 'https://YOUR_AUTH0_DOMAIN/oauth/token',
  headers: { 'content-type': 'application/json' },
  body: '{"grant_type":"authorization_code","client_id": "YOUR_CLIENT_ID","code_verifier": "YOUR_GENERATED_CODE_VERIFIER","code": "YOUR_AUTHORIZATION_CODE","redirect_uri": "https://YOUR_AUTH0_DOMAIN/mobile", }' };

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

NSData *postData = [[NSData alloc] initWithData:[@"{"grant_type":"authorization_code","client_id": "YOUR_CLIENT_ID","code_verifier": "YOUR_GENERATED_CODE_VERIFIER","code": "YOUR_AUTHORIZATION_CODE","redirect_uri": "https://YOUR_AUTH0_DOMAIN/mobile", }" dataUsingEncoding:NSUTF8StringEncoding]];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://YOUR_AUTH0_DOMAIN/oauth/token"]
                                                       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/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\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"https://YOUR_AUTH0_DOMAIN/mobile\", }",
  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 = "{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"https://YOUR_AUTH0_DOMAIN/mobile\", }"

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

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

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

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

url = URI("https://YOUR_AUTH0_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/json'
request.body = "{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"https://YOUR_AUTH0_DOMAIN/mobile\", }"

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

let headers = ["content-type": "application/json"]

let postData = NSData(data: "{"grant_type":"authorization_code","client_id": "YOUR_CLIENT_ID","code_verifier": "YOUR_GENERATED_CODE_VERIFIER","code": "YOUR_AUTHORIZATION_CODE","redirect_uri": "https://YOUR_AUTH0_DOMAIN/mobile", }".dataUsingEncoding(NSUTF8StringEncoding)!)

var request = NSMutableURLRequest(URL: NSURL(string: "https://YOUR_AUTH0_DOMAIN/oauth/token")!,
                                        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()

For details on the request parameters, refer to Execute an Authorization Code Grant Flow with PKCE.

If all goes well, you'll receive an HTTP 200 response with the following payload:

{
  "access_token":"eyJz93a...k4laUWw",
  "refresh_token":"GEbRxBN...edjnXbL",
  "id_token":"eyJ0XAi...4faeEoQ",
  "token_type":"Bearer",
  "expires_in":86400
}

You can use the access_token to call the Authentication API's /userinfo endpoint.

The id_token

Once you've decoded the Id Token, you can extract user information from it. The JSON payload contains the user claims (attributes), as well as metadata, and it will look something like this:

{
  "name": "John Smith",
  "email": "jsmith@example.com",
  "picture": "https://example.com/profile-pic.png",
  "iss": "https://auth0user.auth0.com/",
  "sub": "auth0|581...",
  "aud": "xvt...",
  "exp": 1478113129,
  "iat": 1478077129
}

For additional details, please see our docs on the ID Token and its claims.

For a list of libraries you can use to verify and decode tokens refer to JWT.io.

Example Use Cases

This section covers use cases that illustrate the authentication process using PKCE.

Request the User's Name and Profile Picture

In addition to the usual authentication, this example shows how you can request additional user details.

We assume that your app is capable of generating the appropriate code_verifier and code_challenge.

To return the user's name and picture, add the appropriate scopes to your call to the /authorize endpoint. Therefore, the initial authorization URL is as follows:

https://YOUR_AUTH0_DOMAIN/authorize?
    scope=openid%20name%20picture&
    response_type=code&
    client_id=YOUR_CLIENT_ID&
    code_challenge=CODE_CHALLENGE&
    code_challenge_method=S256&
    redirect_uri=YOUR_AUTH0_DOMAIN/mobile

After the user submits the request, the app receives an TTP 302 response with a URL containing the authorization code at the end: https://YOUR_AUTH0_DOMAIN/callback?code=AUTHORIZATION_CODE

Using the authorization code, you can obtain the ID token by making a POST call to the tokens endpoint.


curl --request POST \
  --url 'https://YOUR_AUTH0_DOMAIN/oauth/token' \
  --header 'content-type: application/json' \
  --data '{"grant_type":"authorization_code","client_id": "YOUR_CLIENT_ID","code_verifier": "YOUR_GENERATED_CODE_VERIFIER","code": "YOUR_AUTHORIZATION_CODE","redirect_uri": "YOUR_AUTH0_DOMAIN/mobile" }'
var client = new RestClient("https://YOUR_AUTH0_DOMAIN/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/json");
request.AddParameter("application/json", "{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"YOUR_AUTH0_DOMAIN/mobile\" }", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
package main

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

func main() {

	url := "https://YOUR_AUTH0_DOMAIN/oauth/token"

	payload := strings.NewReader("{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"YOUR_AUTH0_DOMAIN/mobile\" }")

	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/oauth/token")
  .header("content-type", "application/json")
  .body("{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"YOUR_AUTH0_DOMAIN/mobile\" }")
  .asString();
var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://YOUR_AUTH0_DOMAIN/oauth/token",
  "method": "POST",
  "headers": {
    "content-type": "application/json"
  },
  "processData": false,
  "data": "{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"YOUR_AUTH0_DOMAIN/mobile\" }"
}

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

var options = { method: 'POST',
  url: 'https://YOUR_AUTH0_DOMAIN/oauth/token',
  headers: { 'content-type': 'application/json' },
  body: 
   { grant_type: 'authorization_code',
     client_id: 'YOUR_CLIENT_ID',
     code_verifier: 'YOUR_GENERATED_CODE_VERIFIER',
     code: 'YOUR_AUTHORIZATION_CODE',
     redirect_uri: 'YOUR_AUTH0_DOMAIN/mobile' },
  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 = @{ @"grant_type": @"authorization_code",
                              @"client_id": @"YOUR_CLIENT_ID",
                              @"code_verifier": @"YOUR_GENERATED_CODE_VERIFIER",
                              @"code": @"YOUR_AUTHORIZATION_CODE",
                              @"redirect_uri": @"YOUR_AUTH0_DOMAIN/mobile" };

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

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://YOUR_AUTH0_DOMAIN/oauth/token"]
                                                       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/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\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"YOUR_AUTH0_DOMAIN/mobile\" }",
  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 = "{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"YOUR_AUTH0_DOMAIN/mobile\" }"

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

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

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

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

url = URI("https://YOUR_AUTH0_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/json'
request.body = "{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"YOUR_AUTH0_DOMAIN/mobile\" }"

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

let headers = ["content-type": "application/json"]
let parameters = [
  "grant_type": "authorization_code",
  "client_id": "YOUR_CLIENT_ID",
  "code_verifier": "YOUR_GENERATED_CODE_VERIFIER",
  "code": "YOUR_AUTHORIZATION_CODE",
  "redirect_uri": "YOUR_AUTH0_DOMAIN/mobile"
]

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

var request = NSMutableURLRequest(URL: NSURL(string: "https://YOUR_AUTH0_DOMAIN/oauth/token")!,
                                        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()

If all goes well, you'll receive an HTTP 200 response with the following payload:

{
  "access_token":"eyJz93a...k4laUWw",
  "refresh_token":"GEbRxBN...edjnXbL",
  "id_token":"eyJ0XAi...4faeEoQ",
  "token_type":"Bearer",
  "expires_in":86400
}

By extracting the id_token, which now contains the additional name and picture claims you requested, you'll see something similar to the following once you've decoded the payload:

{
  "name": "auth0user@...",
  "picture": "https://example.com/profile-pic.png",
  "iss": "https://auth0user.auth0.com/",
  "sub": "auth0|581...",
  "aud": "xvt...",
  "exp": 1478113129,
  "iat": 1478077129
}

Request a User Log In with GitHub

You can send a user directly to the GitHub authentication screen by passing the connection parameter and setting its value to github.

Logins with Social Providers

While this example shows how to log in users via GitHub, you can just as easily request that a user log in with other Social providers, such as Google or Facebook.

To do this, configure the appropriate Connection in the Auth0 Dashboard and change the connection value of the call to /authorize to the name of the Connection (google-oauth2 for Google, facebook for Facebook, and so on). You can get the Connection's name from the Settings tab of the Connections page.

Read more:

https://YOUR_AUTH0_DOMAIN/authorize?
    scope=openid%20name%20picture&
    response_type=code&
    client_id=YOUR_CLIENT_ID&
    code_challenge=CODE_CHALLENGE&
    code_challenge_method=S256&
    redirect_uri=https://YOUR_AUTH0_DOMAIN/mobile&
    connection=github

After the user submits the request, the app receives an HTTP 302 response with a URL containing the authorization code at the end: https://YOUR_AUTH0_DOMAIN/callback?code=AUTHORIZATION_CODE

Using the authorization code, you can obtain the ID token by making a POST call to the tokens endpoint.


curl --request POST \
  --url 'https://YOUR_AUTH0_DOMAIN/oauth/token' \
  --header 'content-type: application/json' \
  --data '{"grant_type":"authorization_code","client_id": "YOUR_CLIENT_ID","code_verifier": "YOUR_GENERATED_CODE_VERIFIER","code": "YOUR_AUTHORIZATION_CODE","redirect_uri": "YOUR_AUTH0_DOMAIN/mobile" }'
var client = new RestClient("https://YOUR_AUTH0_DOMAIN/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/json");
request.AddParameter("application/json", "{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"YOUR_AUTH0_DOMAIN/mobile\" }", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
package main

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

func main() {

	url := "https://YOUR_AUTH0_DOMAIN/oauth/token"

	payload := strings.NewReader("{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"YOUR_AUTH0_DOMAIN/mobile\" }")

	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/oauth/token")
  .header("content-type", "application/json")
  .body("{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"YOUR_AUTH0_DOMAIN/mobile\" }")
  .asString();
var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://YOUR_AUTH0_DOMAIN/oauth/token",
  "method": "POST",
  "headers": {
    "content-type": "application/json"
  },
  "processData": false,
  "data": "{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"YOUR_AUTH0_DOMAIN/mobile\" }"
}

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

var options = { method: 'POST',
  url: 'https://YOUR_AUTH0_DOMAIN/oauth/token',
  headers: { 'content-type': 'application/json' },
  body: 
   { grant_type: 'authorization_code',
     client_id: 'YOUR_CLIENT_ID',
     code_verifier: 'YOUR_GENERATED_CODE_VERIFIER',
     code: 'YOUR_AUTHORIZATION_CODE',
     redirect_uri: 'YOUR_AUTH0_DOMAIN/mobile' },
  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 = @{ @"grant_type": @"authorization_code",
                              @"client_id": @"YOUR_CLIENT_ID",
                              @"code_verifier": @"YOUR_GENERATED_CODE_VERIFIER",
                              @"code": @"YOUR_AUTHORIZATION_CODE",
                              @"redirect_uri": @"YOUR_AUTH0_DOMAIN/mobile" };

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

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://YOUR_AUTH0_DOMAIN/oauth/token"]
                                                       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/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\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"YOUR_AUTH0_DOMAIN/mobile\" }",
  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 = "{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"YOUR_AUTH0_DOMAIN/mobile\" }"

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

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

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

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

url = URI("https://YOUR_AUTH0_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/json'
request.body = "{\"grant_type\":\"authorization_code\",\"client_id\": \"YOUR_CLIENT_ID\",\"code_verifier\": \"YOUR_GENERATED_CODE_VERIFIER\",\"code\": \"YOUR_AUTHORIZATION_CODE\",\"redirect_uri\": \"YOUR_AUTH0_DOMAIN/mobile\" }"

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

let headers = ["content-type": "application/json"]
let parameters = [
  "grant_type": "authorization_code",
  "client_id": "YOUR_CLIENT_ID",
  "code_verifier": "YOUR_GENERATED_CODE_VERIFIER",
  "code": "YOUR_AUTHORIZATION_CODE",
  "redirect_uri": "YOUR_AUTH0_DOMAIN/mobile"
]

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

var request = NSMutableURLRequest(URL: NSURL(string: "https://YOUR_AUTH0_DOMAIN/oauth/token")!,
                                        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()

If all goes well, you'll receive an HTTP 200 response with the following payload:

{
  "access_token":"eyJz93a...k4laUWw",
  "refresh_token":"GEbRxBN...edjnXbL",
  "id_token":"eyJ0XAi...4faeEoQ",
  "token_type":"Bearer",
  "expires_in":86400
}

You can pull the user's name, profile picture, and email address from the name, picture, and email claims of the returned id_token. Note that the sub claim contains the user's unique ID as returned from GitHub:

{
  "name": "John Smith",
  "picture": "https://avatars.example.com",
  "email": "jsmith@...",
  "email_verified": true,
  "iss": "https://auth0user.auth0.com/",
  "sub": "github|100...",
  "aud": "xvt...",
  "exp": 1478114742,
  "iat": 1478078742
}