Skip to content

RFC 8693 Token Exchange Provider

Exchanges ID tokens for OAuth2 access tokens with RFC 8693 token exchange, sending the identity token as the subject_token, and refreshes them before expiration.

Package pkg/rfc8693. Snippets assume the common setup; Channel Behavior explains the result channel.

import (
"go.riptides.io/tokenex/pkg/credential"
"go.riptides.io/tokenex/pkg/rfc8693"
)
provider, err := rfc8693.NewCredentialsProvider(ctx, logr.Discard())
if err != nil {
log.Fatalf("new provider: %v", err)
}
credCh, err := provider.GetCredentials(ctx, "https://auth.example.com/oauth2/token", idTokenProvider,
rfc8693.WithAudience("https://api.example.com"),
rfc8693.WithScopes([]string{"api.read"}),
)
if err != nil {
log.Fatalf("get credentials: %v", err)
}
for cred := range credCh {
if cred.Err != nil {
log.Printf("token error: %v", cred.Err)
break
}
tok := cred.Credential.(*credential.Oauth2Creds)
log.Printf("got access token, expires %s", tok.Expiry)
}

The request body is JSON. The subject token type defaults to urn:ietf:params:oauth:token-type:jwt (WithSubjectTokenType changes it). WithActorTokenProvider adds an actor token for delegation, and WithRequestedTokenType and WithAdditionalFields cover endpoint-specific parameters.

rfc8693.GetOpenAICredentials exchanges the identity token at OpenAI’s token endpoint (https://auth.openai.com/oauth/token), using the same request shape as the openai-go workload identity support. ClientID is optional.

credCh, err := rfc8693.GetOpenAICredentials(ctx, logr.Discard(), idTokenProvider, rfc8693.OpenAIWIFConfig{
IdentityProviderID: "...",
ServiceAccountID: "...",
})

Related: Supplying short-lived OpenAI API keys to AI agents with Riptides.