Skip to content
On this page

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 Authorization Code PKCE!

  1. The user clicks Login within the application.

  2. Auth0's SDK creates a cryptographically-random code_verifier and from this generates a code_challenge.

  3. Auth0's SDK redirects the user to the Auth0 Authorization Server (/login endpoint) along with the code_challenge.

  4. Your Auth0 Authorization Server redirects the user to the login and authorization prompt.

  5. 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.

  6. 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.

  7. Auth0's SDK sends this code and the code_verifier (created in step 2) to the Auth0 Authorization Server (/auth/token endpoint).

  8. Your Auth0 Authorization Server verifies the code_challenge and code_verifier.

  9. Your Auth0 Authorization Server responds with an ID Token and Access Token (and optionally, a Refresh Token).

  10. Your application can use the Access Token to call an API to access information about the user.

The API responds with the requested data.

  1. Create application

The create application!

  • Choose Authenticator Type is Authorization PKCE Flow
  • Enter Redirect Url. The Redirect URL is the callback URL after user login success

The create application!

  1. 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

Add user to application!

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

Add user to application!

  1. Integrated

When user want login to system, will redirect to page http://dev.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:

http://dev.token.tci-pf.net/login?clientId=59uXQOdXyfFyWcZmB9IO&code_challenge=15e2b0d3c33891ebb0f1ef609ec419420c20e320ce94c65fbc8c3312448eb225&code_challenge_method=SHA256

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:
json
{
  "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:
javascript
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.dev.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:

json
{
  "redirectUrl": "http://url-callback",
  "code": "aY3hgPCdKzGj6IDYNJrEzgKazZQsAZ1MkfvaQfFoG8mmPIfocs"
}

Step 2: Call API to generate token (Refer to this link)

* Api:
  Name: genTokenApp
  Path: /auth/token
  Payload:
json
{
  "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:
javascript
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.dev.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:

json
{
  "id_token": "",
  "access_token": "",
  "refresh_token": "",
  "exp_access_token": 600 // Time expiration access token is 600 seconds
}
  1. 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:

json
{
  "clientId": "DwSljVC4Ycr5YAv2Qbkf",
  "refresh_token": "",
  "id_token": "",
  "grantType": "refresh_token"
}

Response data:

json
{
  "id_token": "",
  "access_token": "", // New access token
  "refresh_token": "", // New refresh token
  "exp_access_token": 600 // Time expire access token. 600 seconds
}
  1. How to validate the access token rsa 256

Call API to get the login key (Refer to this link)

Example:

javascript
var jwksClient = require('jwks-rsa')
var client = jwksClient({
  jwksUri: 'https://api.dev.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:

json
{
  "iat": 1662607837,
  "iss": "atm",
  "exp": 1662608437,
  "aud": "dIwGvPwelNS3Je6AzH41t",
  "scope": {
    "email": "hao.appuser@yopmail.com",
    "id": "a34fZ4NmtQdXuk1k9_2Vt",
    "firstName": "Hao app user",
    "lastName": ""
  }
}
Authorization Code PKCE has loaded