Skip to main content

Authentication

The OpenTDF SDKs authenticate with an OIDC-compatible identity provider (IdP) to obtain access tokens for the platform. The platform itself is a resource server, not an identity provider — you bring your own IdP (Keycloak is the reference implementation).

Not sure which method to use?

See the Authentication Decision Guide to choose the right approach for your use case.

Client Credentials

The most common authentication method for backend services, scripts, and CI/CD pipelines. Uses an OAuth2 client ID and secret to obtain tokens directly from the IdP.

client, err := sdk.New("http://localhost:8080",
sdk.WithClientCredentials("my-client-id", "my-client-secret", nil),
)
if err != nil {
log.Fatal(err)
}
defer client.Close()

The third parameter accepts optional scopes ([]string). Pass nil to use the IdP defaults.

Token refresh: The SDK automatically obtains a new token when the current one expires. No manual refresh handling is needed.

Token Exchange

Use token exchange (RFC 8693) when you already have a token from another identity system and need to exchange it for one the OpenTDF platform accepts. Common in federated identity and SAML environments.

client, err := sdk.New("http://localhost:8080",
sdk.WithTokenExchange("eyJhbGciOi...", []string{"target-audience"}),
)
if err != nil {
log.Fatal(err)
}
defer client.Close()
  • subjectToken — the existing JWT or SAML assertion to exchange
  • audience — the target audience(s) for the new token

Refresh Token

Use a refresh token for browser-based applications and long-lived sessions where you need to maintain access without re-prompting the user.

JavaScript SDK only

Refresh token authentication is currently available in the JavaScript SDK only. Go and Java SDKs handle token lifecycle differently — see Client Credentials for backend use cases.

import { AuthProviders, OpenTDF } from '@opentdf/sdk';

const authProvider = await AuthProviders.refreshAuthProvider({
clientId: 'my-client-id',
refreshToken: 'refresh-token-from-login-flow',
oidcOrigin: 'http://localhost:8080/auth/realms/opentdf',
exchange: 'refresh',
});

const client = new OpenTDF({
authProvider,
platformUrl: 'http://localhost:8080',
});
await client.ready;

Certificate Exchange (mTLS)

Use certificate-based authentication in environments that require mutual TLS (mTLS) with client certificates.

import "crypto/tls"

tlsConfig := &tls.Config{
Certificates: []tls.Certificate{clientCert},
RootCAs: caCertPool,
}

client, err := sdk.New("https://platform.example.com",
sdk.WithTLSCredentials(tlsConfig, []string{"target-audience"}),
)
if err != nil {
log.Fatal(err)
}
defer client.Close()

Custom Token Source

For advanced integrations where the built-in auth methods don't fit, you can bring your own token provider.

Option A: Standard OAuth2 token source

import "golang.org/x/oauth2"

tokenSource := oauth2.StaticTokenSource(&oauth2.Token{
AccessToken: "pre-obtained-token",
})

client, err := sdk.New("http://localhost:8080",
sdk.WithOAuthAccessTokenSource(tokenSource),
)

Option B: Implement the AccessTokenSource interface

For full control, implement the auth.AccessTokenSource interface:

type AccessTokenSource interface {
AccessToken(ctx context.Context, client *http.Client) (AccessToken, error)
MakeToken(func(jwk.Key) ([]byte, error)) ([]byte, error)
}

DPoP (Sender-Constrained Tokens)

DPoP (Demonstration of Proof-of-Possession) binds access tokens to a cryptographic key pair, preventing token theft and replay attacks. The SDKs handle DPoP automatically in most cases.

SDKDefault behaviorCustomization
GoDPoP key auto-generatedsdk.WithSessionSignerRSA(key) to provide your own RSA key
JavaAlways on (RSA, auto-generated)SDKBuilder.srtSigner(signer) for custom signing
JavaScriptOn by defaultdisableDPoP: true to opt out, dpopKeys for custom keys
warning

Only disable DPoP if your IdP does not support it. DPoP is recommended for production deployments as it provides protection against token exfiltration.