Comment on page
Retrieve and use user access tokens
- 1.Create a project in the Dashboard and retrieve your
client_id
andclient_secret
in the API Credential Menu. - 2.Register the Redirect URL in the API Credential Menu.
To begin the authorization flow, you have to construct a URL like the one that follows, and redirect your user to that URL. Make sure to encode your URL.
https://oauth.swan.io/oauth2/auth?response_type=code&client_id={YOUR_CLIENT_ID}&redirect_uri={YOUR_REGISTRATED_URI}&scope=openid%20offline%20idverified&state=kdqsjdlkjsqdlkqjsdlkjsqd
Here are the available query parameters:
response_type=code
(mandatory) This tells the authorization server that you are initiating the authorization code flow.client_id
(mandatory) The public identifier for the application, obtained in the API Credential Menu of the Dashboard.redirect_uri
(mandatory) Tells the authorization server where to send the user back to after they approve the request. This must be one of the registered URLs in the API Credential Menu in the dashboard. It is required if the client has registered more than one redirection URL.scope=openid%20offline%20idverified
(mandatory) This tells the authorization server that the user would like to connect to Swan through the partner (scopeopenid
) with continued access (scopeoffline
) and that they need to verify their identity if not already done (scopeidverified
).state
(mandatory) to be retransmitted in the query string when redirecting back to youphoneNumber
(optional) to avoid asking the customer to enter their phone number with the international format and URL encoded (Example: %2B33689788967)firstName
(optional) to avoid asking the customer to enter their first name during the user registration. Be very careful to collect the correct information if you use this query param because this data will be used to reset the passcode if the user forgets it.lastName
(optional) to avoid asking the customer to enter their last name during the user registration. Be very careful to collect the correct information if you use this query param because this data will be used to reset the passcode if the user forgets it.birthDate
(optional) to avoid asking the customer to enter their birth date during user registration. Be very careful to collect the correct information if you use this query param because this data will be used to reset the passcode if the user forgets it. The format is YYYY-MM-DD.identificationLevel
(optional) associated to the scopeidVerified
tells the authorization server that you are asking the user to do an identification using the following flowPVID
,Expert
, orQES
Learn more. If you do not provide any value, by default it will beExpert
.onboardingId
(optional) to avoid asking the customer to enter their own address and email if they already did it during onboarding.
All those query params are case sensitive
During the authorization process, the user is redirected to a web page, explaining that we need their phone number and how to connect with Swan.
- If the authorization process is carried out via a mobile phone, they are asked to validate the phone number through a 6-digit code sent by text message.
- If the authorization process is carried out via a desktop, the user will receive a link on their smartphone that will open their browser.
You can display the authorization page in different ways :
- In fullscreen mode. This is the easiest way.
- In a native popup. This is more difficult but we've implemented this at Swan from a desktop because we believe that's the best UX.
For security reasons, It's not possible to embed this authorization web page into an iframe/webview. If you are integrating Swan into a mobile app, you must open it using fullscreen mode with a SafariViewController (iOS) or Custom Chrome Tab (Android). Using an in-application browser allows for browser-based authentication, such as shared authentication states and security contexts, without disrupting the UX by requiring the user to switch applications. Check out this compliant implementation: https://tools.ietf.org/html/rfc8252
If the user approves the request on his mobile, the authorization server will redirect the browser back to the
redirect_uri
you specified, adding a code
and state
to the query string.For example, the user will be redirected back to a URL such as
https://{YOUR_REGISTRATED_URI}?code=dzojzd98dzyuouy987&state=kdqsjdlkjsqdlkqjsdlkjsqd
The
state
value will be the same value that you initially set in the request. You have to check if the state in the redirect matches the state originally set. This protects against CSRF and other related attacks.The
code
is the authorization code generated by the authorization server. This code will expire 10 minutes after being created, so you should not wait to retrieve the access token.You can use the authorization
code
returned in the redirect_uri
and exchange it for an access_token
. This must be done via the Token API, using your client_secret
, which you received with your client_id
.Example OAuth Token request
curl -v -X POST <https://oauth.swan.io/oauth2/token> \\
-d "code={YOUR_USER_AUTHORIZATION_CODE}" \\
-d "client_id={YOUR_CLIENT_ID}" \\
-d "client_secret={YOUR_CLIENT_SECRET}" \\
-d "redirect_uri={YOUR_REGISTRATED_URI}" \\
-d "grant_type=authorization_code"
If you provided the correct
code
, client_id
, client_secret
and redirect_uri
, you should get a successful response with an access_token
and a refresh_token
.Example OAuth Token response
{
"access_token": "{YOUR_USER_ACCESS_TOKEN}",
"expires_in": 3600,
"id_token": "{YOUR_ID_TOKEN}",
"refresh_token": "{YOUR_USER_REFRESH_TOKEN}",
"scope": "openid offline",
"token_type": "bearer"
}
If you get an error or invalid grant, such as
401 Unauthorized
, this could have multiple reasons. It could for example be an invalid client_secret
or an expired code
. The code
is short-lived, so just generate a new one and try again.The access token will expire and needs to be refreshed for continued access. This is done with the
refresh_token
using the same endpoint as used when exchanging the authorization code for an access_token
.Example OAuth Token request
curl -v -X POST <https://oauth.swan.io/oauth2/token> \\
-d "refresh_token={YOUR_REFRESH_TOKEN}" \\
-d "client_id={YOUR_CLIENT_ID}" \\
-d "client_secret={YOUR_CLIENT_SECRET}" \\
-d "grant_type=refresh_token"
If you provided the correct
refresh_token
, client_id
and client_secret
, you should get a successful response with an access_token
and a refresh_token
. A refresh_token
never expire but be careful, one used the previous refresh_token
is invalidated and can't be used to request for a new set of access_token
.Example OAuth Token response
{
"access_token": "{YOUR_USER_ACCESS_TOKEN}",
"expires_in": 3600,
"id_token": "{YOUR_ID_TOKEN}",
"refresh_token": "{YOUR_USER_REFRESH_TOKEN}",
"scope": "openid offline",
"token_type": "bearer"
}
PKCE (RFC 7636) is an extension to the Authorization Code flow to prevent several attacks and to be able to securely perform the OAuth exchange from public clients. This flow is considered best practice when using Single Page Apps (SPA) or Mobile Apps.
PKCE is not available right now.
While we do not support both authorization code flow and authorization code flow with PKCE at the same time, please contact us if you want to go with the PKCE flow.
Your first step is to generate a code verifier and challenge:
- Code verifier: Random URL-safe string with a minimum length of 43 characters."URL-safe" means the random string must be composed only of the following alphabet:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.~_
- Code challenge: Base64 URL-encoded SHA-256 hash of the code verifier
The
code_challenge
is a Base64 URL-encoded SHA256 hash of the code_verifier
. Your app saves the code_verifier
for later, and sends the code_challenge
along with the authorization request to your Authorization Server's /authorize
URL.To begin the authorization flow, you have to construct a URL like the one that follows, and redirect your user to that URL.
https://oauth.swan.io/oauth2/auth?response_type=code&client_id={YOUR_CLIENT_ID} &redirect_uri={YOUR_REGISTRATED_URI}&code_challenge_method=S256&code_challenge={YOUR_CODE_CHALLENGE}&scope=openid%20offline&state=kdqsjdlkjsqdlkqjsdlkjsqd
Here are the available query parameters:
response_type=code
This tells the authorization server that you are initiating the authorization code flow.client_id
The public identifier for the application, obtained in the API Credential Menu of the Dashboard.redirect_uri
Tells the authorization server where to send the user back to after they approve the request and which must be one of the registered URLs in the API Credential Menu in the dashboard. It is required if the client has registered more than one redirection URL.code_challenge_method
is the hash method used to generate the challenge, which is alwaysS256
.code_challenge
is the code challenge used for PKCE.scope=openid%20offline%20idverified
This tells the authorization server that the user would like to connect to Swan through the partner (scope openid) with a continued access (scope offline) and that they need to verify their identity if not already done (scope idverified).state
to be retransmitted in the query string when redirecting back to you (mandatory)
During the authorization process, the user is redirected to a web page, explaining that we need their phone number and how to connect with Swan.
- If the authorization process is carried out via a mobile phone, they are asked to validate the phone number through a 6 digit code sent by text message.
- If the authorization process is carried out via a desktop, the user will receive a link on their smartphone that will open their browser.
You can display the authorization page in different ways :
- In fullscreen mode. This is the easiest way.
- In a popup. This is more difficult but we've implemented this at Swan because we believe that's the best UX.
For security reasons, It's not possible to embed this authorization web page into an iframe. If you are integrating Swan in a mobile app, you must open it using fullscreen mode with a SafariViewController (iOS) and Custom Chrome Tab (Android). Using an in-application browser allows browser-based authentication, such as shared authentication states and security context, without disrupting the UX by requiring the user to switch applications. Check out this compliant implementation: https://tools.ietf.org/html/rfc8252
If the user approves the request on his mobile, the authorization server will redirect the browser back to the
redirect_uri
you specified, adding a code
and state
to the query string.For example, the user will be redirected back to a URL such as
https://{YOUR_REGISTRATED_URI}?code=dzojzd98dzyuouy987&state=kdqsjdlkjsqdlkqjsdlkjsqd
The
state
value will be the same value that you initially set in the request. You have to check if the state in the redirect matches the state originally set. This protects against CSRF and other related attacks.The
code
is the authorization code generated by the authorization server. This code is relatively short-lived.You can use the authorization
code
returned in the redirect_uri
and exchange it for an access_token
. This must be done via the Token API, using you client_id
and your code_verifier
you generated.Example OAuth Token request
curl -v -X POST <https://oauth.swan.io/oauth2/token> \\
-d "code={YOUR_USER_AUTHORIZATION_CODE}" \\
-d "code_verifier={YOUR_CODE_VERIFIER}" \\
-d "client_id={YOUR_CLIENT_ID}" \\
-d "redirect_uri={YOUR_REGISTRATED_URI}" \\
-d "grant_type=authorization_code"
If you provided the correct
code
, code_verifier
, and client_id
, you should get a successful response with an access_token
.Example OAuth Token response
{
"access_token": "{YOUR_USER_ACCESS_TOKEN}",
"expires_in": 3600,
"id_token": "{YOUR_ID_TOKEN}",
"scope": "openid offline",
"token_type": "bearer"
}
Still unclear ? Take a look of this full example of PKCE flow written in Rust :
use headless_chrome::{browser::default_executable, Browser, LaunchOptionsBuilder};
use pkce;
use querystring;
use regex::Regex;
use reqwest::Client;
use serde::{Deserialize, Serialize};
use serde_json::to_string_pretty;
use std::collections::HashMap;
use std::str;
use std::time::Duration;
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Token {
pub access_token: String,
pub expires_in: i64,
pub id_token: String,
pub scope: String,
pub token_type: String,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let code_verify = pkce::code_verifier(128);
let code_verifier = str::from_utf8(&code_verify).unwrap();
let code_challenge = pkce::code_challenge(&code_verify);
// you can find it in your credentials settings on the Swan dashboard
let client_id = "CLIENT_ID_TO_CHANGE";
let state = "RANDOM_STATE_TO_CHANGE";
// don't forget to add it before as authorized redirect URL
let redirect_uri = "REDIRECT_URL_TO_SET";
let url = format!(
"<https://oauth.swan.io/oauth2/auth?{>}",
querystring::stringify(vec![
("response_type", "code"),
("code_challenge", &code_challenge),
("code_challenge_method", "S256"),
("client_id", client_id),
("redirect_uri", redirect_uri),
("scope", "openid offline"),
("state", state),
])
);
println!("\\n> Going to {:#?}", url);
let browser = Browser::new(
LaunchOptionsBuilder::default()
.path(Some(default_executable().unwrap()))
.headless(false)
.build()
.unwrap(),
)?;
let tab = browser.wait_for_initial_tab()?;
tab.navigate_to(&url)?;
tab.wait_for_element_with_custom_timeout("SELECTOR_TO_WAIT_TO_KNOW_WHEN_WE_ARE_ON_REDIRECT_URL", Duration::from_secs(100))?;
let url_with_code = tab.get_url();
let code_query_param_pattern = Regex::new(r"^.*?\\?code=(?P<code>.*?)&scope.*?$").unwrap();
let code = code_query_param_pattern
.captures(&url_with_code)
.unwrap()
.name("code")
.unwrap()
.as_str();
println!("\\n> Finding code {}", code);
let http_client = Client::new();
let mut params = HashMap::new();
let grant_type = "authorization_code";
params.insert("grant_type", grant_type);
params.insert("client_id", client_id);
params.insert("code_verifier", code_verifier);
params.insert("code", code);
params.insert("redirect_uri", redirect_uri);
println!("\\n> Calling token endpoint with");
println!(" grant_type: {}", grant_type);
println!(" client_id: {}", client_id);
println!(" code_verifier: {}", code_verifier);
println!(" code: {}", code);
println!(" redirect_uri: {}", redirect_uri);
let resp: Token = http_client
.post("<https://oauth.swan.io/oauth2/token>")
.form(¶ms)
.send()
.await?
.json()
.await?;
println!(
"
========================================
Token endpoint response
========================================"
);
print!("{}", to_string_pretty(&resp).unwrap());
Ok(())
}
Last modified 7d ago