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.

  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

Section titled “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.

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

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

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('=', '')

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

 

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}
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

{
"access_token": "eyJ0e...",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "VQBrv..."
}
  • 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}
grant_type=refresh_token&client_id={client_id}&code={code}&code_verifier={code_verifier1}&code_challenge={codechallenge2}&code_challenge_method=S256
{
"access_token": "eyJ0e...",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "VQBrv..."
}
  • To decode and verify the TID JWT Token, refer to Decode JWT