Skip to content
API Reference

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.

  • 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
Terminal window
pip install keycardai-oauth

keycardai.oauth

ExportDescription
Client / AsyncClientOAuth client for discovery, registration, and token exchange
TokenResponseParsed token endpoint response
AuthorizationServerMetadataParsed .well-known metadata
pkce.authenticateHigh-level PKCE login flow with browser launch and loopback callback
pkce.OAuthCallbackServerLocal callback receiver for custom PKCE flows
utils.pkceLow-level PKCE code verifier and challenge utilities
GrantType, TokenTypeOAuth enum constants
BearerAuth, BasicAuthHTTP auth strategies for outbound requests
extract_bearer_tokenUtility to extract bearer tokens from headers
OAuthError, TokenExchangeErrorException types
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)
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)

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 httpx
from keycardai.oauth.pkce import authenticate
# Hit the protected resource without a token to get the WWW-Authenticate challenge
async 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)