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.
How it works
Section titled “How it works”The Authorization Code with PKCE flow works as follows:
- The client generates a
code_verifierand derives acode_challengefrom it. - The client sends the
code_challengeto the/oauth/authorizeendpoint. - After successful authentication and authorization, Trimble Identity returns an
authorization_codeto the registeredredirect_uri. - The client sends the
authorization_codeandcode_verifierto the/oauth/tokenendpoint. - Trimble Identity validates the authorization code and the
code_verifier. - The server responds with an
access_token,id_token, and optionally arefresh_token. - The client uses the
access_tokento authorize API requests.
The following diagram shows the Authorization Code with PKCE flow:
Client Types and Authentication Methods
Section titled “Client Types and Authentication Methods”Trimble Identity supports PKCE with different client types.
Public Clients
Section titled “Public Clients”Examples of public clients include:
- Single Page Applications (SPAs)
- Mobile applications
- Desktop applications
Public clients:
- Use PKCE without a
client_secretor other client authentication credentials. - Use the
code_verifierto 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.
Confidential Clients
Section titled “Confidential Clients”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:
Option 1: Authorization Header
Section titled “Option 1: Authorization Header”Use PKCE and send the client credentials using the HTTP Authorization header.
The credentials are Base64-encoded in the following format:
client_id:client_secretThe resulting value is sent as:
Authorization: Basic {Base64(client_id:client_secret)}Option 2: POST Body — Recommended
Section titled “Option 2: POST Body — Recommended”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.
Code Verifier
Section titled “Code Verifier”The code_verifier is a high-entropy random string.
It must:
-
Contain only the following characters:
A-Za-z0-9-._~
-
Be between 43 and 128 characters long.
Example in Python
Section titled “Example in Python”import base64import osimport 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_verifierCode Challenge
Section titled “Code Challenge”The code_challenge is the Base64 URL-encoded SHA-256 hash of the code_verifier.
For PKCE, use the S256 code challenge method.
Example in Python
Section titled “Example in Python”import base64import 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.
Encode Client Credentials
Section titled “Encode Client Credentials”This step applies only to confidential clients that use client authentication.
For the Authorization Header method, Base64-encode the following value:
client_id:client_secretExample in Python
Section titled “Example in Python”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_secretin source code, documentation, or examples. Store it securely and replace it with a placeholder such asyour-client-secret.
Authorization Request
Section titled “Authorization Request”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/authorizeParameters
Section titled “Parameters”| 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 |
redirect_uri
Section titled “redirect_uri”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}/callbackhttp://127.0.0.1:{port}/callbackcom.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_uriin your application configuration.
ui_locales
Section titled “ui_locales”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.
prompt
Section titled “prompt”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. |
login_hint
Section titled “login_hint”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.comThis parameter is optional.
identity_provider
Section titled “identity_provider”The identity_provider parameter allows an application to specify a particular federated identity provider.
For example:
identity_provider=okta_trimbleThis parameter is optional.
For more information, refer to the Federations documentations.
account_id
Section titled “account_id”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.
Example Authorization Request
Section titled “Example Authorization Request”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=S256The 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=S256After successful authentication and authorization, Trimble Identity redirects the browser to the registered redirect_uri with the authorization code.
Example Response
Section titled “Example Response”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_verifierbecause it is required during the token request.
Token Request
Section titled “Token Request”The authorization code is exchanged for tokens using the /oauth/token endpoint.
POST {baseURL}/oauth/tokenThe token request differs slightly depending on the client type.
Public Clients — PKCE Only
Section titled “Public Clients — PKCE Only”Public clients, such as SPAs and mobile applications, use PKCE without a client_secret.
Headers
Section titled “Headers”Content-Type: application/x-www-form-urlencodedParameters
Section titled “Parameters”| 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 |
Example Request
Section titled “Example Request”POST /oauth/tokenHost: stage.id.trimblecloud.comContent-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.
Option 1: Authorization Header
Section titled “Option 1: Authorization Header”Send the client_id and client_secret using the HTTP Authorization header.
Headers
Section titled “Headers”Authorization: Basic {Base64(client_id:client_secret)}Content-Type: application/x-www-form-urlencodedParameters
Section titled “Parameters”| 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 |
Example Request
Section titled “Example Request”POST /oauth/tokenHost: stage.id.trimblecloud.comAuthorization: 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}Option 2: POST Body — Recommended
Section titled “Option 2: POST Body — Recommended”For backward compatibility, confidential clients can send the client_secret in the POST body.
Headers
Section titled “Headers”Content-Type: application/x-www-form-urlencodedParameters
Section titled “Parameters”| 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 |
Example Request
Section titled “Example Request”POST /oauth/tokenHost: stage.id.trimblecloud.comContent-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}Token Response
Section titled “Token Response”For all supported client types, a successful token request returns an access token and ID token, and may also return a refresh token.
Example Response
Section titled “Example Response”{ "access_token": "eyJ0e...", "token_type": "bearer", "expires_in": 3600, "id_token": "eyJ0e...", "refresh_token": "VQBrv..."}Response Parameters
Section titled “Response Parameters”| 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. |
Decode and Verify JWT Tokens
Section titled “Decode and Verify JWT Tokens”- To decode and verify the TID JWT Token, refer to Decode JWT