Skip to content

Authorization Code with PKCE

The Authorization Code with Proof Key for Code Exchange (PKCE) flow is an extension of the Authorization Code grant flow.

PKCE protects the authorization code exchange by requiring the client to prove that it initiated the authorization request.

For public clients, such as Single Page Applications (SPAs) and mobile apps, PKCE can be used without a client_secret.

Confidential clients can combine PKCE with client authentication using a client_secret for additional security.

Note: PKCE was originally designed for public clients such as mobile and desktop applications, but it can also be used by web applications and confidential clients.

The Authorization Code with PKCE flow works as follows:

  1. The client generates a code_verifier and derives a code_challenge from it.
  2. The client sends the code_challenge to the /oauth/authorize endpoint.
  3. After successful authentication and authorization, Trimble Identity returns an authorization_code to the registered redirect_uri.
  4. The client sends the authorization_code and code_verifier to the /oauth/token endpoint.
  5. Trimble Identity validates the authorization code and the code_verifier.
  6. The server responds with an access_token, id_token, and optionally a refresh_token.
  7. The client uses the access_token to authorize API requests.

The following diagram shows the Authorization Code with PKCE flow:


Trimble Identity supports PKCE with different client types.

Examples of public clients include:

  • Single Page Applications (SPAs)
  • Mobile applications
  • Desktop applications

Public clients:

  • Use PKCE without a client_secret or other client authentication credentials.
  • Use the code_verifier to prove that the client requesting the token is the same client that initiated the authorization request.
  • Are suitable for applications that cannot safely store a client_secret.

Examples of confidential clients include backend or server-side applications that can securely store credentials.

Confidential clients can use PKCE along with client authentication.

Trimble Identity supports the following methods for transmitting client credentials:

Use PKCE and send the client credentials using the HTTP Authorization header.

The credentials are Base64-encoded in the following format:

client_id:client_secret

The resulting value is sent as:

Authorization: Basic {Base64(client_id:client_secret)}

Use PKCE and send the client credentials as form parameters in the request body.

client_id={client_id}&client_secret={client_secret}

This method is still supported for backward compatibility with systems that use client credentials in the POST body.


Generate a Code Verifier and Code Challenge

Section titled “Generate a Code Verifier and Code Challenge”

The first step is to generate a new code_verifier and code_challenge.

Generate a new pair for every authorization request.

The code_verifier is a high-entropy random string.

It must:

  • Contain only the following characters:

    • A-Z
    • a-z
    • 0-9
    • -
    • .
    • _
    • ~
  • 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(
r"[^a-zA-Z0-9._~-]+",
"",
code_verifier
)
return code_verifier

The code_challenge is the Base64 URL-encoded SHA-256 hash of the code_verifier.

For PKCE, use the S256 code challenge method.

import base64
import hashlib
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("=", "")

The resulting value is sent to the authorization endpoint as the code_challenge.


This step applies only to confidential clients that use client authentication.

For the Authorization Header method, Base64-encode the following value:

client_id:client_secret
import base64
client_id = "62be6b7d-7fec-4492-8f7d-77e0262226a56"
client_secret = "your-client-secret"
credentials = f"{client_id}:{client_secret}"
encoded = base64.b64encode(
credentials.encode("utf-8")
).decode("utf-8")
print(encoded)

Use the resulting value in the Authorization header:

Authorization: Basic {Base64(client_id:client_secret)}

Important: Do not use a real client_secret in source code, documentation, or examples. Store it securely and replace it with a placeholder such as your-client-secret.


After generating the code_verifier and code_challenge, send the code_challenge to the authorization server.

The authorization request is a GET request to:

GET {baseURL}/oauth/authorize
Parameter Description Required
client_id Application ID registered for the application (UUID). Yes
response_type Must be code for the Authorization Code flow. Refer to our well-known OpenID configuration document for other supported response types and combinations: https://id.trimble.com/.well-known/openid-configuration Yes
scope Space-delimited list of requested scopes. Standard OpenID Connect scopes include openid, profile, and email. Application-specific scopes may vary by TID integration. Yes
redirect_uri Redirect URL registered with Trimble Identity. Yes
code_challenge Code challenge generated from the code_verifier. Yes
code_challenge_method PKCE challenge method. Use S256.(plain text is not supported due to security constraints) Yes
account_id Identifier of the account to be used during authentication. Include this only when a specific account context is required. No
state Random value generated by the client to maintain request state and help protect against request forgery. No
ui_locales Locale used for the Trimble Identity UI. No
prompt Controls the authentication UI behavior. No
login_hint Email address to pre-populate in the sign-in or sign-up page. No
identity_provider Specifies a particular federated identity provider, such as okta_trimble. No
nonce Random value generated by the client to bind the authorization request to the returned id_token and help prevent token replay attacks. The client must verify that the nonce claim in the id_token matches the original value sent in the authorization request. No

The redirect_uri parameter specifies where Trimble Identity redirects the user after successful authentication and authorization.

Trimble Identity supports loopback URLs for local development and testing, as well as application-specific callback URIs for mobile and desktop apps:

  • http://localhost:{port}/callback
  • http://127.0.0.1:{port}/callback
  • com.example.myapp://oauth2/callback

Both localhost and 127.0.0.1 support dynamic ports, allowing you to run multiple applications or instances on different ports during development.

For production environments, use HTTPS URLs with your actual domain registered with Trimble Identity.

Important: The redirect URI must exactly match the registered redirect_uri in your application configuration.

The ui_locales parameter specifies the language/locale that Trimble Identity should use for its UI.

For more information about supported locales and internationalization, refer to the Internationalization documentation.

If the exact locale is unavailable, the UI falls back to the base language before using the user’s browser preference.

The prompt parameter controls how Trimble Identity handles the authentication UI.

Supported values include:

Value Description
none Trimble Identity does not display any UI. If there is no existing SSO session, the request redirects with an error such as login_required.
login Trimble Identity always displays the sign-in UI, even if an SSO session already exists. Use this when the application needs to re-verify the user’s identity before allowing access to sensitive resources, or when you want to force fresh authentication instead of reusing an existing session.
create Trimble Identity displays the sign-up page instead of the sign-in page. Use this when your application needs to direct unknown users to sign up during registration flows, or when you want to route users straight to TID sign-up instead of sign-in.

The login_hint parameter allows an application to provide an email address for the sign-in or sign-up page.

For example:

login_hint=user@example.com

This parameter is optional.

The identity_provider parameter allows an application to specify a particular federated identity provider.

For example:

identity_provider=okta_trimble

This parameter is optional.

For more information, refer to the Federations documentations.

The account_id parameter is optional.

Use this IAM account ID when you need the resulting access_token and id_token JWTs to reflect a specific account context associated with the user.

If account_id is not provided, the default authentication flow proceeds without an explicit account context.

If the account_id is invalid or not associated with the user, Trimble Identity redirects to the configured callback URI with an error response.

The nonce parameter is an OpenID Connect security value used to bind the authorization request to the returned id_token.

Generate a new random value for every authorization request:

nonce={nonce}

The client must store the original value and verify that the nonce claim in the returned id_token matches it exactly. If the values do not match, the token should be rejected.

This parameter is optional, but recommended for OpenID Connect flows that use id_token validation.


GET https://stage.id.trimblecloud.com/oauth/authorize?
client_id={client_id}
&response_type=code
&scope=openid%20profile%20email
&redirect_uri=https://localhost/callback
&state={state}
&account_id={account_id}
&code_challenge={code_challenge}
&code_challenge_method=S256

The actual request should be sent as a single URL.

For example:

https://stage.id.trimblecloud.com/oauth/authorize?client_id={client_id}&response_type=code&scope=openid%20profile%20email&redirect_uri=https://localhost/callback&state={state}&account_id={account_id}&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256

After successful authentication and authorization, Trimble Identity redirects the browser to the registered redirect_uri with the authorization code.

https://localhost/callback?code=1a44a0...&state={state}

The authorization code is short-lived and must be exchanged for tokens at the /oauth/token endpoint.

Important: The client must retain the original code_verifier because it is required during the token request.


The authorization code is exchanged for tokens using the /oauth/token endpoint.

POST {baseURL}/oauth/token

The token request differs slightly depending on the client type.


Public clients, such as SPAs and mobile applications, use PKCE without a client_secret.

Content-Type: application/x-www-form-urlencoded
Parameter Description Required
grant_type Must be authorization_code. Yes
code Authorization code returned by the /oauth/authorize endpoint. Yes
redirect_uri The same redirect URI used in the authorization request. Yes
client_id Application ID (UUID). Yes
code_verifier The original code_verifier generated before the authorization request. Yes
POST /oauth/token
Host: stage.id.trimblecloud.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
client_id={client_id}&
code={code}&
redirect_uri={redirect_uri}&
code_verifier={code_verifier}

Confidential Clients — PKCE + Client Authentication

Section titled “Confidential Clients — PKCE + Client Authentication”

Confidential clients use PKCE together with client authentication.

Trimble Identity supports two methods for sending the client credentials.

Send the client_id and client_secret using the HTTP Authorization header.

Authorization: Basic {Base64(client_id:client_secret)}
Content-Type: application/x-www-form-urlencoded
Parameter Description Required
grant_type Must be authorization_code. Yes
code Authorization code returned by the /oauth/authorize endpoint. Yes
redirect_uri The same redirect URI used in the authorization request. Yes
client_id Application ID (UUID). Yes
code_verifier The original code_verifier generated before the authorization request. Yes
POST /oauth/token
Host: stage.id.trimblecloud.com
Authorization: Basic {Base64(client_id:client_secret)}
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
client_id={client_id}&
code={code}&
redirect_uri={redirect_uri}&
code_verifier={code_verifier}

For backward compatibility, confidential clients can send the client_secret in the POST body.

Content-Type: application/x-www-form-urlencoded
Parameter Description Required
grant_type Must be authorization_code. Yes
code Authorization code returned by the /oauth/authorize endpoint. Yes
redirect_uri The same redirect URI used in the authorization request. Yes
client_id Application ID (UUID). Yes
client_secret Client secret associated with the application. Yes
code_verifier The original code_verifier generated before the authorization request. Yes
POST /oauth/token
Host: stage.id.trimblecloud.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
client_id={client_id}&
client_secret={client_secret}&
code={code}&
redirect_uri={redirect_uri}&
code_verifier={code_verifier}

For all supported client types, a successful token request returns an access token and ID token, and may also return a refresh token.

{
"access_token": "eyJ0e...",
"token_type": "bearer",
"expires_in": 3600,
"id_token": "eyJ0e...",
"refresh_token": "VQBrv..."
}
Parameter Description
access_token Token used to authorize API requests.
token_type Type of access token.
expires_in Lifetime of the access token in seconds.
id_token OpenID Connect ID token containing identity information about the authenticated user.
refresh_token Optional token that can be used to obtain a new access token without requiring the user to authenticate again.

  • To decode and verify the TID JWT Token, refer to Decode JWT