Use refresh tokens for on-behalf-of tokens (Class #2)
Overview
For workflows that last more than one hour and are not repetitive, use the token exchange grant type and request a refresh token for the on-behalf-of token. This allows applications to obtain new access tokens after the initial one expires, supporting long-running, one-time workflows.
How It Works
-
To enable Refresh Tokens for On-Behalf-Of access, teams are required to submit a formal support request including the following mandatory information:
Use Case Questionnaire
Your submitted use case must address the following security and operational questions:
- Business Justification: A formal explanation of why this capability is required for your operations.
- Use Case Description : A detailed overview of the implementation logic, including any relevant supporting documentation.
- Application Details : Specific App ID and App Name
- Environment Details : STAGE or PROD
- First-Party Status : Confirm that these are first-party applications intended strictly for internal use and will not be exposed to third parties.
- Workflow Duration : Provide a technical explanation as to why the specific workflow requires more than one hour to complete.
- Process Frequency : Detail whether this is a repetitive or scheduled process (Note: Class #2 is unsuitable for repetitive/scheduled workflows).
- Business Impact : Define the specific operational or financial consequences if refresh tokens are not enabled for this application.
- Security Measures : Outline the specific protocols and storage mechanisms you will implement to ensure the security of long-lived tokens.
-
Application requests a refresh token during token exchange by including the
offline_accessscope. -
Application stores the refresh token and uses it to obtain new access tokens as needed.
-
Refresh tokens have a finite lifetime (9 days) and cannot be refreshed indefinitely.
Requirements
| Requirement | Details |
|---|---|
| Workflow | Must be long-running and non-repetitive. |
| Eligibility | Access is reserved for internal applications, subject to business case approval. |
| Subject limitation | Must represent a User (not Device or Application). |
| Authentication | Use mTLS for client authentication and DPoP for sender-constrained tokens. |
- Use the mTLS token endpoint with a TID-issued certificate.
- DPoP proof is required for token exchange and refresh token calls.
- Include the
offline_accessscope in the token exchange request.
Token Request
-
API CALL:
- POST
{``mTLS endpoint``}/oauth/token
- POST
-
HEADER:
- Accept: application/json
-
REQUEST BODY:
- grant_type = urn:ietf:params:oauth:grant-type:token-exchange
- subject_token_type= urn:ietf:params:oauth:token-type:jwt
- subject_token= {the on-behalf-of token obtained via token exchange}
- client_id= {Application ID registered in TID/IAM}
- scope= openid offline_access app_name (space separated values)
- client_secret= {Application secret registered in TID/IAM}
mTLS token endpoints:
- Staging:
https://mtls.stage.id.trimblecloud.com - Production:
https://mtls.id.trimble.com
Example Request
POST: /oauth/tokenHost: mtls.stage.id.trimblecloud.comAccept: application/jsonContent-Type: application/x-www-form-urlencodedCache-Control: no-cache
grant_type=urn:ietf:params:oauth:grant-type:token-exchange&scope=openid offline_access app_name&subject_token=eyZui8...<JWT truncated for brevity>&subject_token_type=urn:ietf:params:oauth:token-type:jwt&client_id=********&client_secret=***********Token Response
If the token request succeeds, the server responds with a 200 response code.
A JSON response that is received includes the following values:
- access_token
- expires_in
Example Response
{ "token_type": "DPoP", "expires_in": 3600, "refresh_token": "us_861e9...", "access_token": "eyJhbG...<JWT truncated for brevity>"}- To decode and verify the TID JWT Token, refer to Decode JWT
Using the Refresh Token
Use the refresh token to obtain new access tokens until the maximum validity is reached.
Example Request
POST: /oauth/tokenHost: mtls.stage.id.trimblecloud.comAccept: application/jsonContent-Type: application/x-www-form-urlencodedCache-Control: no-cache
grant_type=refresh_token&scope=openid app_name&refresh_token=us_861e9...&client_id=********Bearer token option for resource servers
If a resource server does not yet support DPoP-bound tokens, you can request a bearer access token by adding a custom claim to the DPoP proof:
"access_token_type": "bearer"- TID will issue a bearer access token instead of a DPoP-bound token.
When this claim is omitted, TID issues a DPoP-bound access token.
The access_token_type claim is honored only when the client requests both an access token and a refresh token from TID.
Best Practices & Troubleshooting
- Initial authentication security level is recorded and enforced for all subsequent calls.
- No protocol switching: All refresh calls must use the same authentication method (mTLS + DPoP).
- Refresh token validity is window-based (9 days max, no extension on refresh).
- Store refresh tokens securely.
- Monitor token expiry and plan for re-authentication.
- Only request refresh tokens when necessary and approved.
- Review error responses for protocol or eligibility issues.