How to get a user access token

Prerequisites

  1. 1.
    Create a project in the Dashboard and retrieve your client_id and client_secret in the API Credential Menu.
  2. 2.
    Register the Redirect URL in the API Credential Menu.

Get an authorization code

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}&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 (scope openid) with continued access (scope offline) and that they need to verify their identity if not already done (scope idverified).
  • state (mandatory) to be retransmitted in the query string when redirecting back to you
  • phoneNumber (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.
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. 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 is relatively short-lived.

Retrieve access tokens

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
1
curl -v -X POST <https://oauth.swan.io/oauth2/token> \\
2
-d "code={YOUR_USER_AUTHORIZATION_CODE}" \\
3
-d "client_id={YOUR_CLIENT_ID}" \\
4
-d "client_secret={YOUR_CLIENT_SECRET}" \\
5
-d "redirect_uri={YOUR_REGISTRATED_URI}" \\
6
-d "grant_type=authorization_code"
Copied!
If you provided the correct code, client_id and client_secret, you should get a successful response with an access_token and a refresh_token.
Example OAuth Token response
1
{
2
"access_token": "{YOUR_USER_ACCESS_TOKEN}",
3
"expires_in": 3600,
4
"id_token": "{YOUR_ID_TOKEN}",
5
"refresh_token": "{YOUR_USER_REFRESH_TOKEN}",
6
"scope": "openid offline",
7
"token_type": "bearer"
8
}
Copied!

In case of errors

If you get an error here, 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.

Refresh token

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
1
curl -v -X POST <https://oauth.swan.io/oauth2/token> \\
2
-d "refresh_token={YOUR_REFRESH_TOKEN}" \\
3
-d "client_id={YOUR_CLIENT_ID}" \\
4
-d "client_secret={YOUR_CLIENT_SECRET}" \\
5
-d "grant_type=refresh_token"
Copied!
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. Be careful, the previous refresh_token is invalidated and can't be used to request for a new set of access_token.
Example OAuth Token response
1
{
2
"access_token": "{YOUR_USER_ACCESS_TOKEN}",
3
"expires_in": 3600,
4
"id_token": "{YOUR_ID_TOKEN}",
5
"refresh_token": "{YOUR_USER_REFRESH_TOKEN}",
6
"scope": "openid offline",
7
"token_type": "bearer"
8
}
Copied!

Get an authorization code using PKCE

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.
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
    You can refer to the official spec appendix to see how to make a "base64 URL-encoded" string.
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_methodis the hash method used to generate the challenge, which is always S256.
  • 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.

Retrieve access tokens

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
1
curl -v -X POST <https://oauth.swan.io/oauth2/token> \\
2
-d "code={YOUR_USER_AUTHORIZATION_CODE}" \\
3
-d "code_verifier={YOUR_CODE_VERIFIER}" \\
4
-d "client_id={YOUR_CLIENT_ID}" \\
5
-d "redirect_uri={YOUR_REGISTRATED_URI}" \\
6
-d "grant_type=authorization_code"
Copied!
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
1
{
2
"access_token": "{YOUR_USER_ACCESS_TOKEN}",
3
"expires_in": 3600,
4
"id_token": "{YOUR_ID_TOKEN}",
5
"scope": "openid offline",
6
"token_type": "bearer"
7
}
Copied!
Still unclear ? Take a look of this full example of PKCE flow written in Rust :
1
use headless_chrome::{browser::default_executable, Browser, LaunchOptionsBuilder};
2
use pkce;
3
use querystring;
4
use regex::Regex;
5
use reqwest::Client;
6
use serde::{Deserialize, Serialize};
7
use serde_json::to_string_pretty;
8
use std::collections::HashMap;
9
use std::str;
10
use std::time::Duration;
11
12
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
13
pub struct Token {
14
pub access_token: String,
15
pub expires_in: i64,
16
pub id_token: String,
17
pub scope: String,
18
pub token_type: String,
19
}
20
21
#[tokio::main]
22
async fn main() -> Result<(), Box<dyn std::error::Error>> {
23
let code_verify = pkce::code_verifier(128);
24
let code_verifier = str::from_utf8(&code_verify).unwrap();
25
let code_challenge = pkce::code_challenge(&code_verify);
26
// you can find it in your credentials settings on the Swan dashboard
27
let client_id = "CLIENT_ID_TO_CHANGE";
28
let state = "RANDOM_STATE_TO_CHANGE";
29
// don't forget to add it before as authorized redirect URL
30
let redirect_uri = "REDIRECT_URL_TO_SET";
31
let url = format!(
32
"<https://oauth.swan.io/oauth2/auth?{>}",
33
querystring::stringify(vec![
34
("response_type", "code"),
35
("code_challenge", &code_challenge),
36
("code_challenge_method", "S256"),
37
("client_id", client_id),
38
("redirect_uri", redirect_uri),
39
("scope", "openid offline"),
40
("state", state),
41
])
42
);
43
println!("\\n> Going to {:#?}", url);
44
45
let browser = Browser::new(
46
LaunchOptionsBuilder::default()
47
.path(Some(default_executable().unwrap()))
48
.headless(false)
49
.build()
50
.unwrap(),
51
)?;
52
let tab = browser.wait_for_initial_tab()?;
53
tab.navigate_to(&url)?;
54
tab.wait_for_element_with_custom_timeout("SELECTOR_TO_WAIT_TO_KNOW_WHEN_WE_ARE_ON_REDIRECT_URL", Duration::from_secs(100))?;
55
let url_with_code = tab.get_url();
56
let code_query_param_pattern = Regex::new(r"^.*?\\?code=(?P<code>.*?)&scope.*?quot;).unwrap();
57
let code = code_query_param_pattern
58
.captures(&url_with_code)
59
.unwrap()
60
.name("code")
61
.unwrap()
62
.as_str();
63
println!("\\n> Finding code {}", code);
64
let http_client = Client::new();
65
let mut params = HashMap::new();
66
let grant_type = "authorization_code";
67
params.insert("grant_type", grant_type);
68
params.insert("client_id", client_id);
69
params.insert("code_verifier", code_verifier);
70
params.insert("code", code);
71
params.insert("redirect_uri", redirect_uri);
72
73
println!("\\n> Calling token endpoint with");
74
println!(" grant_type: {}", grant_type);
75
println!(" client_id: {}", client_id);
76
println!(" code_verifier: {}", code_verifier);
77
println!(" code: {}", code);
78
println!(" redirect_uri: {}", redirect_uri);
79
80
let resp: Token = http_client
81
.post("<https://oauth.swan.io/oauth2/token>")
82
.form(&params)
83
.send()
84
.await?
85
.json()
86
.await?;
87
println!(
88
"
89
========================================
90
Token endpoint response
91
========================================"
92
);
93
print!("{}", to_string_pretty(&resp).unwrap());
94
Ok(())
95
}
Copied!