Skip to content

Serial Refresh with PKCE

Public clients that use Authorization code grant with Proof Key for Code Exchange (PKCE) can use Serial PKCE to refresh their access token. Below are instructions on using Serial PKCE.

How it works

  1. Code_verifier and code_challenge are generated.
  2. Code_challenge is submitted to /authorize endpoint.
  3. The authorization server returns an authorization_code.
  4. On /token request pass the code_verifier equivalent to code_challenge sent in the authorize request and another code_challenge which must be different from the first code_challenge.
  5. The server responds with an OAuth_code, id_token, and an access_token.
  6. The access token can now be used to authorize the application.
  7. On /token request to refresh token pass code_verifier for the last code_challenge and another code_challenge which must be different from the previous one.
  8. On every other /token request to refresh the token always pass the code_verifier corresponding to the last code_challenge and a new code_challenge. If no code_challenge is passed, then the refresh_token generated cannot be used.

Generate a code verifier and challenge code

The first step is the generation of a new code verifier and code challenge. This step must be repeated for every authorization request.

Code verifier

The code verifier string must meet the following requirements:

  • Include only the following characters: A-Z, a-z, 0-9, punctuation characters ._- or ~ (hyphen, period, underscore, and tilde.)
  • The verifier string must be between 43 and 128 characters long.

Example in Python

import base64
import os
import re
def generate_code_verifier(code_length):
   code_verifier = base64.urlsafe_b64encode(os.urandom(code_length)).decode('utf-8')
   code_verifier = re.sub('[^a-zA-Z0-9]+', '', code_verifier)
   return code_verifier

Challenge code

The challenge code is a BASE64-URL-encoded string of the SHA256 hash of the code verifier.

Example in Python

import hashlib
import base64
def to_pkce_challenge(code_verifier):
    code_challenge = hashlib.sha256(code_verifier.encode('utf-8')).digest()
    code_challenge = base64.urlsafe_b64encode(code_challenge).decode('utf-8')
    return code_challenge.replace('=', '')

Authorization Request

After generating the challenge code, it must be submitted to the authorization server in a GET request. The code generated is valid for 10 minutes.

  • API CALL:

    • GET {``baseURL``}/oauth/authorize
  • PARAMETERS:

    • client_id = {Application ID (UUID)}
    • response_type = code
    • scope = openID Application Name (separated by space)
    • redirect_uri = {redirect_uri}
    • code_challenge = {Challenge Code}
    • code_challenge_method = S256
    • state = {string, this value is optional}

Code_challenge_method must be set to S256.

The response should give you the authorization_code you need to send to the server with the code_verifier value.

{redirect_uri}?code={authorization_code}&state=test

Example request:

ttps://stage.id.trimblecloud.com/oauth/authorize?client_id={client_id}&response_type=code&scope=openid processing&redirect_uri=https://trimble.com?code=1a44a0...&state=test&code_challenge=1234ABCD5&code_challenge_method=S256

Example response:

https://stage.id.trimblecloud.com/oauth/authorize?code=1a44a0...&state=test

 

Token request

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

  • API CALL:

    • POST {baseURL}/oauth/token
  • Header

    • Content-Type: application/x-www-form-urlencoded
  • Parameters

    • grant_type = authorization_code
    • code = {code from /auth call}
    • redirect_uri = {redirect_uri}
    • client_id = {Application ID (UUID)}
    • code_verifier = {code_verifier}
    • code_challenge = {Unique code challenge}
    • code_challenge_method = {S256}

Example request

grant_type=authorization_code&client_id={client_id}&code={code}&redirect_uri={redirect_uri}&code_verifier={code_verifier}&code_challenge={codechallenge}&code_challenge_method=S256

Example response

{
"access_token": "eyJ0e...",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "VQBrv..."
}

Refresh token request example

  • API CALL:

    • POST {baseURL}/oauth/token
  • Parameters

    • grant_type = refresh_token
    • refresh_token = {refesh_token}
    • client_id = {Application ID (UUID)}
    • code_verifier = {code_verifier}
    • code_challenge = {Unique code challenge}
    • code_challenge_method = {S256}

Example request

grant_type=refresh_token&client_id={client_id}&code={code}&code_verifier={code_verifier1}&code_challenge={codechallenge2}&code_challenge_method=S256

Example response

{
"access_token": "eyJ0e...",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "VQBrv..."
}
  • To decode and verify the TID JWT Token, refer to Decode JWT