Configure and Implement Native to Web SSO
Configure Native to Web SSO
To use Native to Web Single Sign-On (SSO), configure your native and web (Single Page App or Regular Web App) to create and manage sessions with the Auth0 Management API. You need an access token to use the Management API.
To configure Native to Web SSO, you need to create and manage session_transfer_tokens and configure your native and web applications.
Create and manage Session Transfer Tokens
The first Management API call allows your native and web Applications to:
Create and manage
session_transfer_tokens
Create sessions in a web browser via cookies or a URL parameter
Bind the session to a user's device through an IP address or ASN
For existing applications, make a PATCH
call to the Update a Client endpoint. To create a new application, make a POST
call to the Create a Client endpoint:
{
"session_transfer": {
"can_create_session_transfer_token": false,
"allowed_authentication_methods": ["cookie", "query"],
"enforce_device_binding": "ip", // also "none" or "asn"
}
}
Was this helpful?
Parameter | Type | Value | Description |
---|---|---|---|
can_create_session_transfer_token |
Boolean, default = false |
N/A | Specifies whether the application can use the Token Exchange endpoint to create a session_transfer_token . |
allowed_authentication_methods |
Array of enum, default =[] |
cookie , query |
Determines the methods allowed for a web application to create a session using a session_transfer_token :
cookie takes precedence if both methods are allowed. |
enforce_device_binding |
Enum, default = ip |
none , ip , asn |
Configures the level of device binding enforced when a session_transfer_token is consumed:
|
Configure native applications
Once a user is authenticated, Auth0 returns an Access token, and ID token, and (optionally) a Refresh token.
You can configure your native application to exchange a refresh token for a Session Transfer Token. If your web application does not support cookie injection, your native application also needs to configure your web application’s Login URI to inject the Session Transfer Token as a URI parameter.
You can update your native application using the Update a Client endpoint:
curl --request PATCH \
--url 'https://{yourDomain}/api/v2/clients//{yourClientId}' \
--header 'authorization: Bearer {yourMgmtApiAccessToken}' \
--header 'content-type: application/json' \
--data '{
"session_transfer": {
"can_create_session_transfer_token": true,
"enforce_device_binding": "ip"
}
}'
Was this helpful?
var client = new RestClient("https://{yourDomain}/api/v2/clients//{yourClientId}");
var request = new RestRequest(Method.PATCH);
request.AddHeader("authorization", "Bearer {yourMgmtApiAccessToken}");
request.AddHeader("content-type", "application/json");
request.AddParameter("application/json", "{\n \"session_transfer\": {\n \"can_create_session_transfer_token\": true,\n \"enforce_device_binding\": \"ip\"\n }\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Was this helpful?
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/api/v2/clients//{yourClientId}"
payload := strings.NewReader("{\n \"session_transfer\": {\n \"can_create_session_transfer_token\": true,\n \"enforce_device_binding\": \"ip\"\n }\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("authorization", "Bearer {yourMgmtApiAccessToken}")
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))
}
Was this helpful?
HttpResponse<String> response = Unirest.patch("https://{yourDomain}/api/v2/clients//{yourClientId}")
.header("authorization", "Bearer {yourMgmtApiAccessToken}")
.header("content-type", "application/json")
.body("{\n \"session_transfer\": {\n \"can_create_session_transfer_token\": true,\n \"enforce_device_binding\": \"ip\"\n }\n}")
.asString();
Was this helpful?
var axios = require("axios").default;
var options = {
method: 'PATCH',
url: 'https://{yourDomain}/api/v2/clients//{yourClientId}',
headers: {
authorization: 'Bearer {yourMgmtApiAccessToken}',
'content-type': 'application/json'
},
data: {
session_transfer: {can_create_session_transfer_token: true, enforce_device_binding: 'ip'}
}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
Was this helpful?
#import <Foundation/Foundation.h>
NSDictionary *headers = @{ @"authorization": @"Bearer {yourMgmtApiAccessToken}",
@"content-type": @"application/json" };
NSDictionary *parameters = @{ @"session_transfer": @{ @"can_create_session_transfer_token": @YES, @"enforce_device_binding": @"ip" } };
NSData *postData = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://{yourDomain}/api/v2/clients//{yourClientId}"]
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];
Was this helpful?
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/api/v2/clients//{yourClientId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => "{\n \"session_transfer\": {\n \"can_create_session_transfer_token\": true,\n \"enforce_device_binding\": \"ip\"\n }\n}",
CURLOPT_HTTPHEADER => [
"authorization: Bearer {yourMgmtApiAccessToken}",
"content-type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
Was this helpful?
import http.client
conn = http.client.HTTPSConnection("")
payload = "{\n \"session_transfer\": {\n \"can_create_session_transfer_token\": true,\n \"enforce_device_binding\": \"ip\"\n }\n}"
headers = {
'authorization': "Bearer {yourMgmtApiAccessToken}",
'content-type': "application/json"
}
conn.request("PATCH", "/{yourDomain}/api/v2/clients//{yourClientId}", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
Was this helpful?
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/api/v2/clients//{yourClientId}")
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["authorization"] = 'Bearer {yourMgmtApiAccessToken}'
request["content-type"] = 'application/json'
request.body = "{\n \"session_transfer\": {\n \"can_create_session_transfer_token\": true,\n \"enforce_device_binding\": \"ip\"\n }\n}"
response = http.request(request)
puts response.read_body
Was this helpful?
import Foundation
let headers = [
"authorization": "Bearer {yourMgmtApiAccessToken}",
"content-type": "application/json"
]
let parameters = ["session_transfer": [
"can_create_session_transfer_token": true,
"enforce_device_binding": "ip"
]] as [String : Any]
let postData = JSONSerialization.data(withJSONObject: parameters, options: [])
let request = NSMutableURLRequest(url: NSURL(string: "https://{yourDomain}/api/v2/clients//{yourClientId}")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "PATCH"
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)
}
})
dataTask.resume()
Was this helpful?
Configure web applications
Before you enable Session Transfer Token, make sure you have configured your web application’s Application Login URI to handle extra parameters. To learn more about URIs, read Application Settings.
You can update the web application using the Update a Client endpoint:
curl --request PATCH \
--url 'https://{yourDomain}/api/v2/clients//{yourClientId}' \
--header 'authorization: Bearer {yourMgmtApiAccessToken}' \
--header 'content-type: application/json' \
--data '{
"session_transfer": {
"allowed_authentication_methods": ["cookie", "query"]
}
}'
Was this helpful?
var client = new RestClient("https://{yourDomain}/api/v2/clients//{yourClientId}");
var request = new RestRequest(Method.PATCH);
request.AddHeader("authorization", "Bearer {yourMgmtApiAccessToken}");
request.AddHeader("content-type", "application/json");
request.AddParameter("application/json", "{\n \"session_transfer\": {\n \"allowed_authentication_methods\": [\"cookie\", \"query\"]\n }\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Was this helpful?
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/api/v2/clients//{yourClientId}"
payload := strings.NewReader("{\n \"session_transfer\": {\n \"allowed_authentication_methods\": [\"cookie\", \"query\"]\n }\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("authorization", "Bearer {yourMgmtApiAccessToken}")
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))
}
Was this helpful?
HttpResponse<String> response = Unirest.patch("https://{yourDomain}/api/v2/clients//{yourClientId}")
.header("authorization", "Bearer {yourMgmtApiAccessToken}")
.header("content-type", "application/json")
.body("{\n \"session_transfer\": {\n \"allowed_authentication_methods\": [\"cookie\", \"query\"]\n }\n}")
.asString();
Was this helpful?
var axios = require("axios").default;
var options = {
method: 'PATCH',
url: 'https://{yourDomain}/api/v2/clients//{yourClientId}',
headers: {
authorization: 'Bearer {yourMgmtApiAccessToken}',
'content-type': 'application/json'
},
data: {session_transfer: {allowed_authentication_methods: ['cookie', 'query']}}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
Was this helpful?
#import <Foundation/Foundation.h>
NSDictionary *headers = @{ @"authorization": @"Bearer {yourMgmtApiAccessToken}",
@"content-type": @"application/json" };
NSDictionary *parameters = @{ @"session_transfer": @{ @"allowed_authentication_methods": @[ @"cookie", @"query" ] } };
NSData *postData = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://{yourDomain}/api/v2/clients//{yourClientId}"]
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];
Was this helpful?
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/api/v2/clients//{yourClientId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => "{\n \"session_transfer\": {\n \"allowed_authentication_methods\": [\"cookie\", \"query\"]\n }\n}",
CURLOPT_HTTPHEADER => [
"authorization: Bearer {yourMgmtApiAccessToken}",
"content-type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
Was this helpful?
import http.client
conn = http.client.HTTPSConnection("")
payload = "{\n \"session_transfer\": {\n \"allowed_authentication_methods\": [\"cookie\", \"query\"]\n }\n}"
headers = {
'authorization': "Bearer {yourMgmtApiAccessToken}",
'content-type': "application/json"
}
conn.request("PATCH", "/{yourDomain}/api/v2/clients//{yourClientId}", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
Was this helpful?
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/api/v2/clients//{yourClientId}")
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["authorization"] = 'Bearer {yourMgmtApiAccessToken}'
request["content-type"] = 'application/json'
request.body = "{\n \"session_transfer\": {\n \"allowed_authentication_methods\": [\"cookie\", \"query\"]\n }\n}"
response = http.request(request)
puts response.read_body
Was this helpful?
import Foundation
let headers = [
"authorization": "Bearer {yourMgmtApiAccessToken}",
"content-type": "application/json"
]
let parameters = ["session_transfer": ["allowed_authentication_methods": ["cookie", "query"]]] as [String : Any]
let postData = JSONSerialization.data(withJSONObject: parameters, options: [])
let request = NSMutableURLRequest(url: NSURL(string: "https://{yourDomain}/api/v2/clients//{yourClientId}")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "PATCH"
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)
}
})
dataTask.resume()
Was this helpful?
Implement Native to Web SSO
Native to Web Single SSO provides a seamless user experience transitioning authenticated users from your native application to your web application.
To facilitate this, your native application needs to exchange a refresh token for a Session Transfer Token and send the Session Transfer Token, through a URL or cookie, to your web application to authorize the session.
In your native application
Step 1: Exchanging a Refresh Token for a Session Transfer Token
Use the /token endpoint with your native application to exchange the refresh token for a Session Transfer Token.
import SwiftUI
import Auth0
import WebKit
struct MainView: View {
var body: some View {
Button("Open Web Session", action: self.launchWebSSO)
}
func launchWebSSO() {
Auth0
.authentication()
.ssoExchange(withRefreshToken: refreshToken)
.start { result in
switch result {
case .success(let ssoCredentials):
DispatchQueue.main.async {
let cookie = HTTPCookie(properties: [
.domain: "{yourDomain}",
.path: "/",
.name: "auth0_session_transfer_token",
.value: ssoCredentials.sessionTransferToken,
.expires: ssoCredentials.expiresIn,
.secure: true
])!
let webView = WKWebView()
let store = webView.configuration.websiteDataStore.httpCookieStore
store.setCookie(cookie) {
let url = URL(string: "https://yourWebApplicationLoginURI")!
let request = URLRequest(url: url)
webView.load(request)
let vc = UIViewController()
vc.view = webView
UIApplication.shared.windows.first?.rootViewController?.present(vc, animated: true)
}
}
case .failure(let error):
print("Failed to get SSO token: \(error)")
}
}
}
}
Was this helpful?
import android.app.Activity
import android.util.Log
import android.webkit.CookieManager
import android.webkit.WebView
fun launchWebSSO(context: Activity) {
authentication
.ssoExchange("refresh_token")
.start(object : Callback<SSOCredentials, AuthenticationException> {
override fun onSuccess(result: SSOCredentials) {
val cookieManager = CookieManager.getInstance()
val cookieValue = "auth0_session_transfer_token=" + result.sessionTransferToken +
"; Path=/; Secure; HttpOnly; SameSite=None"
cookieManager.setAcceptCookie(true)
cookieManager.setCookie("{yourDomain}", cookieValue)
val webView = WebView(context)
webView.settings.javaScriptEnabled = true
webView.loadUrl("https://yourWebApplicationLoginURI")
context.runOnUiThread {
context.setContentView(webView)
}
}
override fun onFailure(exception: AuthenticationException) {
Log.e("Auth0", "Failed to get session transfer token", exception)
}
})
}
Was this helpful?
{
"method": "POST",
"url": "https://{yourDomain}/oauth/token",
"headers": [
{
"name": "Content-Type",
"value": "application/x-www-form-urlencoded"
}
],
"postData": {
"mimeType": "application/x-www-form-urlencoded",
"params": [
{
"name": "grant_type",
"value": "refresh_token"
},
{
"name": "client_id",
"value": "{yourClientId}"
},
{
"name": "refresh_token",
"value": "YOUR_REFRESH_TOKEN"
},
{
"name": "audience",
"value": "urn:YOUR_AUTH0_TENANT_DOMAIN:session_transfer"
}
]
}
}
Was this helpful?
The Auth0 tenant returns a single-use and short-lived (1-minute lifetime) session_transfer_token.
{
"access_token": "{session_transfer_token}",
"issued_token_type": "urn:auth0:params:oauth:token-type:session_transfer_token",
"token_type": "N_A",
"expires_in": 60
}
Was this helpful?
Step 2: Send the Session Transfer Token through a URL or cookie
There are two options to send the session_transfer_token
to your web application based on the configured allowed_authentication_methods
.
Option 1: Send the session_transfer_token as a cookie
If your web application using WebView or browser supports cookie injection, you can configure your native application to:
Add the session_transfer_token into a cookie.
Open the web application using WebView or browser.
Log the web application to your Auth0 tenant or Custom Domain. As the
session_transfer_token
is included in the cookie, the user is not prompted for first-factor authentication.
{
"method": "GET",
"url": "https://YOUR_WEB_APPLICATION_LOGIN_URL/",
"cookie": [
{
"name": "auth0_session_transfer_token",
"value": "YOUR_SESSION_TRANSFER_TOKEN; Path=/; Secure; HttpOnly; SameSite=None"
}
]
}
Was this helpful?
Option 2: Send the session_transfer_token as a URL parameter
If your web application does not support cookie injection, you can configure your native application using URL parameters to:
Add the session_transfer_token as a URL parameter.
Open the web application using WebView or browser.
Log the web application appending the
session_transfer_token
as a URL parameter to the /authorize endpoint. The Auth0 tenant authenticates the user without requiring first-factor authentication, as the session_transfer_token is valid and trusted
{
"method": "GET",
"url": "https://YOUR_WEB_APP_LOGIN_URL?session_transfer_token=YOUR_SESSION_TRANSFER_TOKEN",
"headers": []
}
Was this helpful?
In your web application
Implement Native to Web Web Single SSO in your web application using URL parameters by:
Option 1: Add the Session Transfer Token in your web application request
Use the /authorize
endpoint with your web application when the session_transfer_token is sent as a URL parameter.
{
"method": "GET",
"url": "https://YOUR_WEB_APP_LOGIN_URL?session_transfer_token=YOUR_SESSION_TRANSFER_TOKEN",
"headers": []
}
Was this helpful?
Option 2: Add the Session Transfer Token to web applications using Auth0 SDKs
Auth0 SDKs do not support Native to Web Single SSO automatically and they will not include the session_transfer_token
in the /authorize
endpoint request.
Below are examples of web applications using Auth0 SDKs to redirect the session_transfer_token
in the /authorize
endpoint request:
Node (Express.js)
If your web application uses Express.js or the Auth0 Express SDK, you can use the code below to add middleware support for session_transfer_token
.
const config = {
authRequired: false,
auth0Logout: true
};
// Default Middleware with no customizations
// app.use(auth(config));
// Extending the middleware to auto detect session_transfer_token
app.use((req, res, next) => {
const { session_transfer_token } = req.query;
if (session_transfer_token) {
config.authorizationParams = {
session_transfer_token,
}
}
auth(config)(req, res, next);
});
Was this helpful?
SAML and WS-Federation
If your web application uses SAML or WS-Fed service provider and Auth0 as the IdP, you can send the session_transfer_token
as an URL parameter to the Auth0 /authorize
endpoint and the redirect_uri
is the SAML or WS-Fed sign-in URL.
{
"method": "GET",
"url": "https://{yourDomain}/samlp/{yourClientId}",
"headers": [
{
"name": "Cookie",
"value": "session_transfer_token=YOUR_SESSION_TRANSFER_TOKEN"
}
],
"queryString": [
{
"name": "session_transfer_token",
"value": "YOUR_SESSION_TRANSFER_TOKEN"
}
]
}
Was this helpful?
Session Transfer Token with Actions
Using session_transfer_token
with Actions allows you to configure post-authentication risk detection and response capabilities to enhance user protection.
To facilitate this, the post-login Action object event.session_transfer_token provides relevant information including unique client_id
, scope
, request
information such as ip
, asn
, user_agent
and geoip
information such as, cityName
, countryCode
among others. To learn more, read Actions Triggers: post-login - Event Object.
The Action code below allows you to dynamically reject a transaction based on geolocation information:
/**
* Handler that will be called during the execution of a PostLogin flow.
*
* @param {Event} event - Details about the user and the context in which they are logging in.
* @param {PostLoginAPI} api - Interface whose methods can be used to change the behavior of the login.
*/
exports.onExecutePostLogin = async (event, api) => {
if(
event.session_transfer_token &&
event.session_transfer_token.request.geoip.countryCode !== event.request.geoip.countryCode
) {
api.access.deny("Network mismatch detected")
}
};
Was this helpful?
Monitoring
You can monitor the Native to Web SSO activity by reviewing the Tenant logs.
sertft
: Successful Refresh Token exchange. This log will correspond to a Native to Web SSO exchange when theaudience
field is"audience":"urn:$auth0Domain:session_transfer"
fertft
: Failed Refresh Token exchange. This log will correspond to a Native to Web SSO exchange when theaudience
field is"audience": "urn:$auth0Domain:session_transfer"