Skip to content

Use refresh tokens for on-behalf-of tokens (Class #2)

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.

  1. 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.
  2. Application requests a refresh token during token exchange by including the offline_access scope.

  3. Application stores the refresh token and uses it to obtain new access tokens as needed.

  4. Refresh tokens have a finite lifetime (9 days) and cannot be refreshed indefinitely.


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_access scope in the token exchange request.
  • API CALL:

    • POST {``mTLS endpoint``}/oauth/token
  • 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
POST: /oauth/token
Host: mtls.stage.id.trimblecloud.com
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Cache-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=***********

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
{
  "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

Use the refresh token to obtain new access tokens until the maximum validity is reached.

POST: /oauth/token
Host: mtls.stage.id.trimblecloud.com
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
grant_type=refresh_token&scope=openid app_name&refresh_token=us_861e9...&client_id=********

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.


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