Authentication Decision Guide
How to choose the right authentication method for your OpenTDF integration, based on your environment and use case.
How Authentication Works in OpenTDF
The OpenTDF platform is a resource server — it does not manage user identities or issue tokens. Instead, you bring your own OIDC-compatible identity provider (IdP), such as Keycloak (the reference implementation), and configure the platform to trust it.
The authentication flow looks like this:
Your choice of authentication method determines how your application obtains tokens from the IdP. The platform validates tokens against a trusted issuer, but a valid token alone is not sufficient — the token must also carry the correct audience (aud), required claims, and scopes for the request to succeed.
Choose Your Authentication Method
Use this flowchart to find the right method for your situation:
Scenario Matrix
| Scenario | Recommended Method | Notes |
|---|---|---|
| Backend service / microservice | Client Credentials | Most straightforward. Use clientCredentialsTokenProvider() — it caches tokens and auto-refreshes on expiry. |
| Web application (browser) with refresh token | Refresh Token | JS SDK only. Use refreshTokenProvider() with a refresh token from your OIDC login flow. Handles automatic renewal. |
| Web application (browser) with access token only | Access Token | JS SDK only. Use authTokenInterceptor() with a function that returns your access token. Use when your IdP doesn't issue refresh tokens. |
| CLI tool (interactive user) | otdfctl auth login | Opens a browser for OIDC login. See CLI auth docs. |
| CI/CD pipeline / automated job | Client Credentials | Use a dedicated service account. Rotate secrets regularly. |
| Federated identity / SAML | Token Exchange | Exchange an existing token for one the platform accepts. |
| mTLS environment | Certificate Exchange | Uses client certificates for transport-level auth. |
| Custom IdP integration | Custom Token Source | Implement the token provider interface in your SDK. |
Getting Started
Client Credentials (Backend Services)
The simplest path. Register a client in your IdP, then use clientCredentialsTokenProvider() (JS) or pass the client ID and secret directly (Go/Java). The SDK handles token acquisition, caching, and refresh automatically.
What you need: A client ID and client secret from your IdP.
See SDK code examples for Go, Java, and JavaScript.
OIDC Login Flow (Browser Apps)
For browser-based applications, your app completes an OIDC Authorization Code flow to obtain an access token and (optionally) a refresh token from the IdP.
- If you have a refresh token, use
refreshTokenProvider()— it handles token exchange and automatic renewal. - If you only have an access token (because your IdP doesn't issue refresh tokens or the grant is disabled for security reasons), use
authTokenInterceptor()with a function that returns your token.
See SDK code examples: Refresh Token | Access Token (JavaScript only).
Token Exchange (Federated Identity)
When your application already has a token from another identity system (SAML, external JWT), use token exchange to swap it for a token the platform trusts.
What you need: A valid JWT or SAML assertion from the source identity system.
See SDK code examples for Go, Java, and JavaScript.
Certificate Exchange (mTLS)
In environments that require mutual TLS, the SDK can use client certificates to authenticate with the IdP.
What you need: A client certificate and private key, plus the CA certificate chain.
See SDK code examples for Go and Java.
CLI Authentication
For interactive CLI usage, otdfctl handles authentication for you:
# Interactive login (opens browser)
otdfctl auth login --endpoint http://localhost:8080
# Non-interactive (for scripts)
otdfctl auth client-credentials --client-id my-client --client-secret my-secret
# Print your current access token (useful for debugging)
otdfctl auth print-access-token
See the CLI auth command reference for all options.
Development vs Production
Local Development
The OpenTDF quickstart runs Keycloak with pre-configured defaults:
| Setting | Default value |
|---|---|
| Platform endpoint | http://localhost:8080 |
| OIDC origin | http://localhost:8888/auth/realms/opentdf |
| Client ID | opentdf |
| Client secret | secret |
| TLS | Disabled (plaintext) |
| DPoP | Enabled |
These defaults are for development only. Do not use them in production.
Production Checklist
OpenTDF does not prescribe a specific deployment strategy. This checklist covers authentication-related concerns — your infrastructure, scaling, and orchestration choices are up to you.
- Enable TLS — All connections to the platform and IdP must use HTTPS
- Use strong client secrets — Generate long, random secrets and store them securely (vault, environment variables — never in code)
- Rotate secrets regularly — Automate secret rotation where possible
- Restrict scopes — Request only the scopes your application needs
- Enable DPoP — Sender-constrained tokens protect against token theft (see DPoP docs)
- Set appropriate token lifetimes — Short-lived access tokens with refresh tokens where applicable
- Use a production-grade IdP — Configure Keycloak (or your chosen IdP) for high availability, backups, and monitoring
- Configure CORS — Your application's origin must be registered as an allowed origin in both the IdP and the OpenTDF platform
Common Pitfalls
"I'm getting 401 Unauthorized"
- Check your IdP URL. The platform discovers the IdP via its well-known OIDC endpoint. Verify the
oidcOrigin(JS), token endpoint (Go), or platform endpoint (Java) is correct. - Verify the client exists. Ensure the client ID is registered in your IdP and the secret matches.
- Check token audience. The platform rejects tokens whose
audclaim doesn't match the expected audience. Decode your token (e.g., at jwt.io) and verify theaudfield matches what's configured in your platform's YAML config under the auth section. - Check CORS. For browser-based apps, your application's origin must be allowed in both the IdP and OpenTDF platform configuration. CORS errors often appear as opaque network failures rather than clear 401 responses.
"My token expired and I'm getting errors"
- Client credentials: The built-in
clientCredentialsTokenProvider()(JS) and Go/Java SDKs refresh automatically — if you're seeing expiry errors, check that your IdP is reachable. - OAuth token source (Go):
WithOAuthAccessTokenSourcedoes not auto-refresh. YourTokenSourceimplementation must handle refresh. - Refresh token (JS):
refreshTokenProvider()handles rotation automatically, but ensure the initial refresh token itself hasn't expired. Long-lived refresh tokens can be configured in your IdP.
"DPoP-related errors"
- IdP doesn't support DPoP: Disable it with
disableDPoP: true(JS) or configure your IdP to accept DPoP proofs. - Clock skew: DPoP proofs include a timestamp. Ensure your server and IdP clocks are synchronized (NTP).
- Key mismatch: If you provide custom DPoP keys, ensure the same key pair is used for the lifetime of the session.
"TLS/certificate errors"
- Self-signed certs in development: Use
useInsecurePlaintextConnection(true)(Java) or configure your TLS settings to trust the development CA. - Missing CA certs: Ensure the platform's CA certificate is in your trust store.