Appearance
Authorization Code PKCE
When public clients (e.g., native and single-page applications) request Access Tokens, some additional security concerns are posed that are not mitigated by the Authorization Code Flow alone. This is because:
Native apps
Cannot securely store a Client Secret. Decompiling the app will reveal the Client Secret, which is bound to the app and is the same for all users and devices.
May make use of a custom URL scheme to capture redirects (e.g., MyApp://) potentially allowing malicious applications to receive an Authorization Code from your Authorization Server.
Single-page apps
Cannot securely store a Client Secret because their entire source is available to the browser.
Given these situations, OAuth 2.0 provides a version of the Authorization Code Flow which makes use of a Proof Key for Code Exchange (PKCE) (defined in OAuth 2.0 RFC 7636).
The PKCE-enhanced Authorization Code Flow introduces a secret created by the calling application that can be verified by the authorization server; this secret is called the Code Verifier. Additionally, the calling app creates a transform value of the Code Verifier called the Code Challenge and sends this value over HTTPS to retrieve an Authorization Code. This way, a malicious attacker can only intercept the Authorization Code, and they cannot exchange it for a token without the Code Verifier.
Instructions on how to integrate authorization code PKCE flow 
The user clicks Login within the application.
Auth0's SDK creates a cryptographically-random code_verifier and from this generates a code_challenge.
Auth0's SDK redirects the user to the Auth0 Authorization Server (/login endpoint) along with the code_challenge.
Your Auth0 Authorization Server redirects the user to the login and authorization prompt.
The user authenticates using one of the configured login options and may see a consent page listing the permissions Auth0 will give to the application.
Your Auth0 Authorization Server stores the code_challenge and redirects the user back to the application with an authorization code, which is good for one use.
Auth0's SDK sends this code and the code_verifier (created in step 2) to the Auth0 Authorization Server (/auth/token endpoint).
Your Auth0 Authorization Server verifies the code_challenge and code_verifier.
Your Auth0 Authorization Server responds with an ID Token and Access Token (and optionally, a Refresh Token).
Your application can use the Access Token to call an API to access information about the user.
The API responds with the requested data.
- Create application
- Access the Application page
- Click on the Create button

- Choose
Authenticator TypeisAuthorization PKCE Flow - Enter Redirect Url. The Redirect URL is the callback URL after user login success

- Add user to application
- On the applications grid, click on the edit icon of record where you want to edit the application
- Click on tab Application Users
- Click on the Create button

- Input data: First name, Email. Password and Confirm Password
- Click on the Save button

- Integrated
When user want login to system, will redirect to page http://stg.token.tci-pf.net/login?clientId=&code_challenge=&code_challenge_method=. With clientId is provided when creating application, the code_challenge is encrypt plant text, code_challenge_method is method encrypt. Currently, the ATM system only supports 2 methods SHA246 and SHA512. Example:
After user login successfully, ATM will auto redirect url with code. Example: http://localhost:8080/callback?code=k2j5QFYN66ob0H5H12e50EorNkwxKgLV0XaRjnY9guF9kt8bex.
Now that you've acquired an authorization_code and have been granted permission by the user, you can redeem the code for an access_token to the resource. Redeem the code by sending a POST request to the /auth/token endpoint. Example:
Step 1: Call API to login (Refer to this link)
* Api:
Name: authenticationApp
Path: /auth
Method: POST
Payload:
{
"loginId": "end.user13@gmail.com",
"password": "H123456789",
"clientId": "OJJvmTmatjCOTuqBxur2",
"code_challenge": "code_challenge",
"code_challenge_method":"SHA256"
}
- loginId: Email of user's application
- password: Password of user's application
- clientId: Get from application
- code_challenge: generate a SHA-256 hexadecimal hash from string
- code_challenge_method: Support SHA256/SHA512
Example:
var axios = require('axios');
const { createHash } = require('crypto');
const code_challenge = createHash('sha256').update('123456789').digest('hex')
s
var data = JSON.stringify({
"loginId": "end.user13@gmail.com",
"password": "H123456789",
"clientId": "OJJvmTmatjCOTuqBxur2",
"code_challenge": code_challenge,
"code_challenge_method":"SHA256"
});
var config = {
method: 'post',
url: 'https://api.stg.token.tci-pf.net/auth',
headers: {
'Content-Type': 'application/json'
},
data : data
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
Response data:
{
"redirectUrl":"http://url-callback",
"code": "aY3hgPCdKzGj6IDYNJrEzgKazZQsAZ1MkfvaQfFoG8mmPIfocs"
}
Step 2: Call API to generate token (Refer to this link)
* Api:
Name: genTokenApp
Path: /auth/token
Payload:
{
"clientId": "MXSAUwpZycuhd2owvV2j",
"clientSecret": "QhRhyGuSTP7S9cU6riqR3vPHETq9vErX",
"grant_types": "authorization_code",
"code": "aY3hgPCdKzGj6IDYNJrEzgKazZQsAZ1MkfvaQfFoG8mmPIfocs",
"code_verifier": "123456789"
}
- clientId: Get from application
- clientSecret: Get from application
- code_verifier: code before hash
- grant_types: "authorization_code"
Example:
var axios = require('axios');
var data = JSON.stringify({
"clientId": "MXSAUwpZycuhd2owvV2j",
"clientSecret": "QhRhyGuSTP7S9cU6riqR3vPHETq9vErX",
"grant_types": "authorization_code",
"code": "aY3hgPCdKzGj6IDYNJrEzgKazZQsAZ1MkfvaQfFoG8mmPIfocs",
"code_verifier": "123456789"
});
var config = {
method: 'post',
url: 'https://api.stg.token.tci-pf.net/auth/token',
headers: {
'Content-Type': 'application/json'
},
data : data
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
Response data:
{
"id_token": "",
"access_token": "",
"refresh_token": "",
"exp_access_token": 600 // Time expiration access token is 600 seconds
}
- Refresh the access token
Access tokens are short lived. Refresh them after they expire to continue accessing resources. You can do so by submitting another POST request to the /auth/token endpoint. Provide the refresh_token instead of the code (Refer to this link). Example:
{
"clientId": "DwSljVC4Ycr5YAv2Qbkf",
"refresh_token": "",
"id_token": "",
"grantType": "refresh_token"
}
Response data:
{
"id_token":"",
"access_token":"", // New access token
"refresh_token":"", // New refresh token
"exp_access_token": 600 // Time expire access token. 600 seconds
}
- How to validate the access token rsa 256
Call API to get the login key (Refer to this link)
Example:
var jwksClient = require('jwks-rsa');
var client = jwksClient({
jwksUri: 'https://api.stg.token.tci-pf.net/auth/.well-known/jwks.json'
});
function getKey(header, callback){
client.getSigningKey(header.kid, function(err, key) {
var signingKey = key.publicKey || key.rsaPublicKey;
callback(null, signingKey);
});
}
jwt.verify(token, getKey, options, function(err, decoded) {
console.log(decoded.foo)
});
Decoded token:
{
"iat": 1662607837,
"iss": "atm",
"exp": 1662608437,
"aud": "dIwGvPwelNS3Je6AzH41t",
"scope": {
"email": "hao.appuser@yopmail.com",
"id": "a34fZ4NmtQdXuk1k9_2Vt",
"firstName": "Hao app user",
"lastName": ""
}
}