OAuth Primitives
Low-level OAuth 2.0 primitives for discovery, token exchange, and JWT operations.
The OAuth package provides pure OAuth 2.0 primitives with no MCP dependency. Use it when you need direct control over OAuth flows or are building outside the MCP framework.
When to Use
Section titled “When to Use”- Custom OAuth flows outside of MCP
- Token exchange (RFC 8693) for delegated access
- Authorization server discovery
- JWT signing and verification
- Building your own auth middleware
Installation
Section titled “Installation”pip install keycardai-oauthnpm install @keycardai/oauthgo get github.com/keycardai/credentials-go/oauthKey Exports
Section titled “Key Exports”keycardai.oauth
| Export | Description |
|---|---|
Client / AsyncClient | OAuth client for discovery, registration, and token exchange |
TokenResponse | Parsed token endpoint response |
AuthorizationServerMetadata | Parsed .well-known metadata |
pkce.authenticate | High-level PKCE login flow with browser launch and loopback callback |
pkce.OAuthCallbackServer | Local callback receiver for custom PKCE flows |
utils.pkce | Low-level PKCE code verifier and challenge utilities |
GrantType, TokenType | OAuth enum constants |
BearerAuth, BasicAuth | HTTP auth strategies for outbound requests |
extract_bearer_token | Utility to extract bearer tokens from headers |
OAuthError, TokenExchangeError | Exception types |
@keycardai/oauth
| Export | Description |
|---|---|
fetchAuthorizationServerMetadata | Discover OAuth server configuration |
TokenExchangeClient | RFC 8693 token exchange client |
authenticate | High-level PKCE login flow (Node.js only) |
generatePkcePair | Generate a PKCE code verifier and challenge pair |
JWKSOAuthKeyring | JWKS key management for signing and verification |
JWTSigner / JWTVerifier | JWT creation and validation |
base64url | URL-safe base64 encoding utilities |
HTTPError, OAuthError | Error types |
credentials-go/oauth
| Export | Description |
|---|---|
FetchAuthorizationServerMetadata | Discover OAuth server configuration |
TokenExchangeClient | RFC 8693 token exchange client |
JWKSOAuthKeyring | JWKS key management with two-level caching |
JWTSigner / JWTVerifier | JWT creation and validation |
PEMPrivateKeyring | Private key management from PEM-encoded keys |
AuthorizationServerMetadata | Parsed .well-known metadata |
Quickstart
Section titled “Quickstart”Discover Authorization Server Metadata
Section titled “Discover Authorization Server Metadata”from keycardai.oauth import Client
zone_url = "https://your-zone.keycard.ai"
with Client(zone_url) as client: metadata = client.discover_server_metadata() print(metadata.issuer) print(metadata.token_endpoint)import { fetchAuthorizationServerMetadata } from "@keycardai/oauth";
const zoneUrl = "https://your-zone.keycard.ai";const metadata = await fetchAuthorizationServerMetadata(zoneUrl);
console.log(metadata.issuer);console.log(metadata.token_endpoint);import "github.com/keycardai/credentials-go/oauth"
zoneURL := "https://your-zone.keycard.ai"metadata, err := oauth.FetchAuthorizationServerMetadata(ctx, zoneURL)if err != nil { log.Fatal(err)}
fmt.Println(metadata.Issuer)fmt.Println(metadata.TokenEndpoint)Token Exchange
Section titled “Token Exchange”from keycardai.oauth import Client, GrantType
with Client(zone_url) as client: response = client.token_exchange( subject_token="<user-access-token>", resource="https://api.github.com", ) print(response.access_token)import { TokenExchangeClient } from "@keycardai/oauth";
const client = new TokenExchangeClient({ tokenEndpoint: metadata.token_endpoint, clientId: "your-client-id", clientSecret: "your-client-secret",});
const response = await client.exchange({ subjectToken: "<user-access-token>", resource: "https://api.github.com",});
console.log(response.access_token);import "github.com/keycardai/credentials-go/oauth"
client := oauth.NewTokenExchangeClient( zoneURL, oauth.WithClientCredentials("your-client-id", "your-client-secret"),)
response, err := client.Exchange(ctx, &oauth.TokenExchangeRequest{ SubjectToken: "<user-access-token>", Resource: "https://api.github.com",})if err != nil { log.Fatal(err)}
fmt.Println(response.AccessToken)User Login with PKCE
Section titled “User Login with PKCE”Use this flow when a CLI tool, desktop app, or MCP client needs to log a user in through their browser. The authenticate() helper opens the user’s browser at the authorize endpoint, runs a local callback server, and exchanges the authorization code for tokens.
import httpxfrom keycardai.oauth.pkce import authenticate
# Hit the protected resource without a token to get the WWW-Authenticate challengeasync with httpx.AsyncClient() as http: response = await http.get("<resource-url>") challenge = response.headers["www-authenticate"]
token = await authenticate( client_id="<client-id>", resource_url="<resource-url>", www_authenticate_header=challenge, scopes=["read:data"],)print(token.access_token)import { authenticate } from "@keycardai/oauth";
const token = await authenticate("https://<zone-id>.keycard.cloud", { clientId: "<client-id>", scopes: ["read:data"],});
console.log(token.access_token);authenticate() requires Node.js. It uses node:http and node:child_process to run the local callback server and open the browser.
Related
Section titled “Related”SEE ALSO