oauth

package
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 18, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package oauth implements the OAuth authorization-code flow with PKCE for remote providers that support it (currently Anthropic). It provides the PKCE primitives, the loopback callback server, and the per-provider flow driver (authorize URL, token exchange, refresh, identity bootstrap).

Index

Constants

View Source
const ChallengeMethod = "S256"

ChallengeMethod is the PKCE challenge method, always "S256".

View Source
const DeviceGrantType = "urn:ietf:params:oauth:grant-type:device_code"

DeviceGrantType is the RFC 8628 grant type for device-code token requests.

Variables

This section is empty.

Functions

func AuthorizeURL

func AuthorizeURL(def provider.Definition, challenge, state, redirectURI string) string

AuthorizeURL builds the authorization-code flow URL for the user to open. The provider's AuthorizeURL, ClientID, Scopes, and AuthorizeParams are taken from def; challenge and state are generated by the caller (pkce.go).

func ExpiresAt

func ExpiresAt(expiresIn int) time.Time

ExpiresAt converts an expires_in seconds value to an absolute time.

func GenerateChallenge

func GenerateChallenge(verifier string) string

GenerateChallenge returns the S256 PKCE code challenge for verifier: BASE64URL(SHA256(verifier)). S256 is the only method Anthropic accepts.

func GenerateState

func GenerateState() (string, error)

GenerateState returns a random hex-encoded CSRF state parameter. The state ties the callback to the authorize request that started the flow; the callback server rejects any callback whose state does not match.

func GenerateVerifier

func GenerateVerifier() (string, error)

GenerateVerifier returns a high-entropy PKCE code verifier: verifierLen random bytes, base64url-encoded (no padding). The verifier is sent in the token exchange; the challenge derived from it is sent in the authorize request.

Types

type CallbackResult

type CallbackResult struct {
	Code  string
	State string
	Err   error // non-nil if the provider sent an error or state mismatched
}

CallbackResult is what the loopback server delivers when the OAuth provider redirects back. Code is the authorization code to exchange; State is the CSRF state the provider echoed back (must match what we sent).

type CallbackServer

type CallbackServer struct {
	// contains filtered or unexported fields
}

CallbackServer is a transient HTTP server that listens on localhost for the OAuth redirect. It exists for the duration of one authorization-code flow: Start it, open the authorize URL, wait on Result(), then it shuts down.

func NewCallbackServer

func NewCallbackServer(port int, path, host, expectedState string) *CallbackServer

NewCallbackServer creates a server bound to localhost:port. expectedState is the CSRF state we sent in the authorize request; the callback is rejected if the provider's echo does not match. path is the URL path to register (e.g. "/callback", "/auth/callback"). host is the hostname used in the redirect URI ("localhost" or "127.0.0.1").

func (*CallbackServer) Port

func (cs *CallbackServer) Port() int

Port returns the actual bound port (useful if Start picked a random one, though Anthropic does not allow port fallback).

func (*CallbackServer) Start

func (cs *CallbackServer) Start() (string, error)

Start binds the listener and begins serving. It returns the full redirect URI the provider should use (http://localhost:{port}/callback).

func (*CallbackServer) Wait

Wait blocks until the callback is received or ctx is cancelled. The server is shut down before returning.

type DeviceResponse

type DeviceResponse struct {
	DeviceCode              string `json:"device_code"`
	UserCode                string `json:"user_code"`
	VerificationURI         string `json:"verification_uri"`
	VerificationURIComplete string `json:"verification_uri_complete"`
	Interval                int    `json:"interval"`
	ExpiresIn               int    `json:"expires_in"`
}

DeviceResponse is the result of a device authorization request (RFC 8628 §3.1).

func RequestDeviceCode

func RequestDeviceCode(ctx context.Context, def provider.Definition) (DeviceResponse, error)

RequestDeviceCode starts a device-code flow by POSTing to the provider's device authorization endpoint. The returned DeviceResponse contains the user code and verification URI to display to the user.

type Identity

type Identity struct {
	AccountID string
	Email     string
	OrgID     string
	OrgName   string
}

Identity is the account/org info recovered after a token exchange.

func FetchIdentity

func FetchIdentity(ctx context.Context, def provider.Definition, accessToken string) (Identity, error)

FetchIdentity recovers account info after a token exchange. It dispatches based on def.IdentityMethod: "bootstrap" calls Anthropic's claude_cli endpoint, "userinfo" calls a standard OIDC userinfo endpoint. Returns a zero Identity (no error) if IdentityURL is empty.

type TokenResponse

type TokenResponse struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
	ExpiresIn    int    `json:"expires_in"`
	TokenType    string `json:"token_type"`
	Scope        string `json:"scope"`
}

TokenResponse is the result of a token exchange or refresh. The fields map to standard OAuth 2.0 token endpoint responses.

func Exchange

func Exchange(ctx context.Context, def provider.Definition, code, codeVerifier, redirectURI, state string) (TokenResponse, error)

Exchange trades an authorization code for access and refresh tokens. codeVerifier must match the challenge sent in AuthorizeURL. If def has a ClientSecret, it is included in the request (required by confidential clients like Google).

func PollDeviceToken

func PollDeviceToken(ctx context.Context, def provider.Definition, dr DeviceResponse) (TokenResponse, error)

PollDeviceToken polls the token endpoint until the user authorizes the device, the device code expires, or ctx is cancelled. It returns the token response on success or an error on failure.

func Refresh

func Refresh(ctx context.Context, def provider.Definition, refreshToken string) (TokenResponse, error)

Refresh exchanges a refresh token for a new access token. The new response may include a new refresh_token (rotation); the caller should persist it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL