Certificate-Based Authentication (mTLS)
Overview
Certificate-Based Authentication using Mutual TLS (mTLS) provides a secure way for applications to connect to TID without using client secrets. Your application uses a digital certificate to prove its identity, improving security and reliability for enterprise integrations, automated workflows, and secure system-to-system communication.
When to Use mTLS
| Use Case | Description |
|---|---|
| Applications without secrets (client_credentials) | When storing a client secret is not feasible or secure |
| Use refresh tokens for on-behalf-of tokens (Class #2) (urn:ietf:params:oauth:grant-type:token-exchange, refresh_token) | Long-running, non-repetitive workflows (> 1 hour) that need sender-constrained tokens with mTLS + DPoP |
| Use subject delegation for long-running repetitive workflows (Class #3) (urn:ietf:params:oauth:grant-type:subject-delegation) | Repetitive workflows (> 1 hour) where applications act on behalf of users without the user being present |
| Device authentication (urn:trimble:params:oauth:x509-cert) | IoT devices authenticate using mTLS with TID-provisioned certificates to obtain access tokens |
| F2C Token Exchange (urn:ietf:params:oauth:grant-type:token-exchange) | Controller-to-sensor delegation where sensors without internet access delegate authority to a nearby controller |
How it Works
- Obtain a certificate for your application from IAM.
- Application presents the certificate during the mTLS handshake to the
/oauth/tokenendpoint. - TID verifies the certificate and issues a certificate-bound access token.
- Application uses the access token to access protected APIs.

mTLS token endpoints:
- Staging:
https://mtls.stage.id.trimblecloud.com - Production:
https://mtls.id.trimble.com
Certificate Management
1. Subscribe to IAM APIs in Cloud Console
mTLS certificates are provisioned by IAM. To obtain an mTLS certificate, the application requesting the certificate must subscribe to the IAM APIs in Cloud Console.
2. Generate the Certificate Signing Request (CSR)
Generate an RSA 2048-bit key pair and create a CSR. You can use either the openssl CLI or Python.
Using OpenSSL (CLI):
openssl req -new -newkey rsa:2048 -nodes -keyout myapp_private_key.pem -out myapp_csr.pemUsing Python:
import jsonimport datetimefrom cryptography import x509from cryptography.hazmat.primitives import hashes, serializationfrom cryptography.hazmat.primitives.asymmetric import rsafrom cryptography.x509.oid import NameOID
CERT_NAME = "EXAMPLE_CERTIFICATE"
# Origination timestamp of the client key pairorigination_timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")cert_cn = f"{CERT_NAME}-{origination_timestamp}"
# Generate RSA 2048-bit keyskeys = rsa.generate_private_key(public_exponent=65537, key_size=2048)
# Generate a CSRbuilder = x509.CertificateSigningRequestBuilder(subject_name=x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, cert_cn)]))csr = builder.sign(keys, hashes.SHA256())csr_pem = csr.public_bytes(serialization.Encoding.PEM)
# Write the private key and CSR to fileswith open("client.private_key.pem", "wb") as f: f.write(keys.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption() ))
with open("client.csr.pem", "wb") as f: f.write(csr_pem)
# Build the IAM API request bodyapi_req_body = json.dumps({"csr": csr_pem.decode("ascii")})with open("iam_api_req_body.json", "w") as f: f.write(api_req_body)
print("CSR PEM:")print(csr_pem.decode("ascii"))3. Submit the CSR to IAM
Use the IAM API to add a new certificate by submitting the CSR created in the previous step.
Request
POST {IAM_baseurl}/applications/{applicationId}/certificatesAuthorization: Bearer {<respective-application-token>}Content-Type: application/jsonRequest body
{ "csr": "{PEM-encoded certificate signing request string}"}Response
{ "fingerprint": "{fingerprint string}", "certificate": "{public certificate string}"}4. Certificate Issuance and Installation
- TID will validate your CSR and issue a new certificate (e.g., a
.crtor.pemfile). - Download the issued certificate from the response.
- Install the new certificate in your application, pairing it with the private key you generated in Step 2.
5. Rotate on Expiry
- Create a new CSR and repeat the process to obtain a new certificate before the current one expires.
- Update your application’s configuration to use the new certificate and private key.
- Test authentication to ensure the new certificate is working.
- Remove the old certificate (Work In Progress) from your application once the new one is active.
Note: Each application can have a maximum of 5 active certificates at any given time. Plan certificate rotation and management accordingly.
Certificate Lifecycle and Rotation
- Certificates have a defined lifespan (validity period: 3 years*) as per security guidelines.
- Rotate certificates before expiry or if compromise is suspected.
- Each application can have up to 5 active certificates.
* Subject to change.
Client Credentials Grant with mTLS
Token Request
-
API CALL:
- POST
{mTLS endpoint}/oauth/token
- POST
-
HEADER:
- Accept: application/json
-
REQUEST BODY:
- grant_type = client_credentials
- scope = {ApplicationNames} (Space separated values)
- client_id = {Application ID registered in TID/IAM}
Example Token Request
POST /oauth/token HTTP/1.1Host: mtls.stage.id.trimblecloud.comContent-Type: application/x-www-form-urlencodedAccept: application/json
grant_type=client_credentials&client_id=ada20a37-372a-42f3-ac25-1290fed75ad7&scope=Automation-Test-App-421925030555583Example Token Response
{ "token_type": "bearer", "expires_in": 3600, "access_token": "eyJhbG...<JWT truncated for brevity>"}- To decode and verify the TID JWT Token, refer to Decode JWT
Certificate-Bound Access Tokens (Proof of Possession)
To provide strong sender-constrained security, access tokens are bound to the client certificate:
- When a client authenticates with mTLS at the
/tokenendpoint, the Authorization Server includes a confirmation claim (cnf) in the JWT access token. - The
cnfclaim contains thex5t#S256field, which is the SHA-256 hash of the client certificate.
Example JWT claims:
{ "iss": "https://id.trimble.com", "exp": 1769586829, "nbf": 1769583229, "iat": 1769583229, "jti": "296200815e2549d8802cb41146344473", "jwt_ver": 2, "sub": "ada20a37-372a-42f3-ac25-1290fed75ad7", "application_name": "Automation-Test-App-421925030555583", "identity_type": "application", "auth_time": 1769583229, "amr": [ "client_credentials" ], "cnf": { "x5t#S256": "71692eb0806248bb8898c38a5356b8321b7548dbc81afd605c2f1313b834993c" }, "aud": [ "ada20a37-372a-42f3-ac25-1290fed75ad7" ], "scope": "Automation-Test-App-421925030555583"}Standards and Implementation Details
RFC 8705: OAuth 2.0 Mutual-TLS Client Authentication
This implementation follows RFC 8705, which defines how OAuth 2.0 clients can authenticate using Mutual TLS (mTLS) and how access tokens can be bound to client certificates for Proof of Possession (PoP).
Client Authentication Methods
TID supports the following client authentication methods for mTLS and client secrets:
tls_client_auth: For certificates issued by a trusted Certificate Authority (CA).client_secret_basic: Standard client secret authentication.client_secret_post: Client secret sent in the POST body.
Clients must register their certificate details (subject DN or public key) with TID.
The OAuth 2.0 Authorization Server Metadata endpoint (https://id.trimble.com/.well-known/openid-configuration) advertises these supported methods in the token_endpoint_auth_methods_supported array.
Error Handling & Troubleshooting
| Error | Description | Action |
|---|---|---|
| Invalid CSR | Malformed or missing fields | Regenerate CSR with correct fields |
| Certificate Expired | Certificate is no longer valid | Rotate certificate and update app |
| Certificate Mismatch | Certificate does not match app/private key | Ensure correct pair is used |
| Revoked Certificate | Certificate has been revoked | Register new certificate |
| Invalid Client | client_id is incorrect or not registered | Verify client_id and registration |
| Invalid Certificate | Certificate is invalid or untrusted | Use valid, non-expired certificate |
| Unauthorized | Client not authorized for token/resource | Check permissions and scopes |
| Token Expired | Access token expired | Request new token |
Best Practices
- Store private keys securely and never share them.
- Rotate certificates proactively.
- Monitor certificate expiry and set up alerts.
- Automate rotation if possible.
- Do not reuse old certificates; generate a new CSR for each rotation.