auth

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Jun 7, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package auth implements OAuth 2.0 PKCE flow scaffolding for bee.

Generic by design: no provider is hard-coded. Users add OAuth client_id + endpoints under [providers.<name>.oauth] in ~/.bee/config.toml, then run /login <name> to drive the flow and persist tokens under ~/.bee/auth/.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildAuthorizeURL

func BuildAuthorizeURL(authorizeEndpoint, clientID, redirectURI, codeChallenge, state, scope string) string

BuildAuthorizeURL composes the full authorize URL with PKCE params.

func BuildAuthorizeURLWithExtras

func BuildAuthorizeURLWithExtras(authorizeEndpoint, clientID, redirectURI, codeChallenge, state, scope string, extras map[string]string) string

BuildAuthorizeURLWithExtras is like BuildAuthorizeURL but appends extra vendor-specific params (audience, prompt, id_token_hint). Extras override standard params if they collide — caller's responsibility.

func Challenge

func Challenge(verifier string) string

Challenge returns base64url(sha256(verifier)) — the S256 PKCE challenge.

func DefaultDir

func DefaultDir() (string, error)

DefaultDir returns ~/.bee/auth, creating it 0700 if missing.

func DeleteAPIKey

func DeleteAPIKey(dir, provider string) error

DeleteAPIKey removes the saved key file. No-op when missing.

func DeleteToken

func DeleteToken(dir, provider string) error

DeleteToken removes the token file. No-op if missing.

func ExtractClaim

func ExtractClaim(jwt, path string) string

ExtractClaim decodes the unverified payload of a JWT and returns the value of the named claim, or "" if absent/non-string.

path supports two forms:

  • "foo" → top-level "foo"
  • "https://example.com/x.bar" → nested: first segment is the FULL claim name (URI claims allowed), subsequent dot-separated segments traverse into the nested object.

No signature verification. Caller must ensure the JWT came from a trusted source (e.g. just-completed TLS-secured OAuth exchange).

func GenerateVerifier

func GenerateVerifier() (string, error)

GenerateVerifier returns a 43-128 char URL-safe code_verifier per RFC 7636. Uses 64 random bytes -> 86 chars after base64url-no-pad. Cryptographically strong.

func HasAPIKey

func HasAPIKey(dir, provider string) bool

HasAPIKey reports whether a key file exists for provider (best-effort — errors are treated as "no key" so callers don't have to fan out error handling for a probe).

func LoadAPIKey

func LoadAPIKey(dir, provider string) (string, error)

LoadAPIKey reads a previously saved api key. Returns ("", nil) if the file is absent — callers fall back to env / treat as unauthenticated.

func SaveAPIKey

func SaveAPIKey(dir, provider, key string) error

SaveAPIKey writes a plain-text api key to <dir>/<provider>.key with 0600 perms. Used for providers that authenticate via static api keys (no oauth flow) when the user enters one through /login. Empty keys are rejected.

func SaveToken

func SaveToken(dir, provider string, tok *Token) error

SaveToken writes tok to <dir>/<provider>.json with 0600 perms.

Types

type CallbackResult

type CallbackResult struct {
	Code  string
	State string
	Err   error
}

CallbackResult holds the auth code from the OAuth redirect.

type LoginConfig

type LoginConfig struct {
	ClientID          string
	AuthorizeEndpoint string
	TokenEndpoint     string
	Scope             string
	RedirectPath      string
	Stdout            io.Writer
	// RedirectPort pins the loopback port (0 = random). Some providers
	// require an exact registered redirect_uri.
	RedirectPort int
	// ExtraAuthorizeParams are merged into the authorize URL query string
	// (e.g. {"audience": "..."}).
	ExtraAuthorizeParams map[string]string
	// AccountIDClaim, when set, instructs Login to decode id_token and
	// extract this claim path into Token.AccountID. Dotted path; first
	// segment may be a fully-qualified URI claim (e.g.
	// "https://api.openai.com/auth.chatgpt_account_id").
	AccountIDClaim string
}

LoginConfig captures everything Login needs to drive the PKCE flow.

type LoopbackServer

type LoopbackServer struct {
	URL    string
	Result <-chan CallbackResult
	// contains filtered or unexported fields
}

LoopbackServer runs a one-shot HTTP server on a random localhost port. The caller registers s.URL as the redirect_uri, opens the authorize URL in a browser, and reads exactly one value from Result.

func StartLoopback

func StartLoopback(ctx context.Context, path string) (*LoopbackServer, error)

StartLoopback binds 127.0.0.1:<random> and serves a single handler at path (defaults to /callback). Context cancellation triggers shutdown.

func StartLoopbackOn

func StartLoopbackOn(ctx context.Context, path string, fixedPort int) (*LoopbackServer, error)

StartLoopbackOn is like StartLoopback but binds to a fixed port. Pass 0 for random. Used when the provider requires an exact redirect_uri match.

func (*LoopbackServer) Close

func (s *LoopbackServer) Close() error

Close stops the loopback server. Safe to call multiple times.

type Token

type Token struct {
	AccessToken  string    `json:"access_token"`
	RefreshToken string    `json:"refresh_token,omitempty"`
	ExpiresIn    int       `json:"expires_in"`
	TokenType    string    `json:"token_type"`
	IssuedAt     time.Time `json:"issued_at"`
	// IDToken is the OIDC id_token, when the provider returns one. Carries
	// per-account claims like ChatGPT's chatgpt_account_id.
	IDToken string `json:"id_token,omitempty"`
	// AccountID is extracted from IDToken at login time and cached so the
	// provider adapter doesn't re-decode the JWT on every request.
	AccountID string `json:"account_id,omitempty"`
}

Token mirrors the standard OAuth 2.0 token endpoint response.

func ExchangeCode

func ExchangeCode(ctx context.Context, tokenURL, clientID, code, verifier, redirectURI string) (*Token, error)

ExchangeCode swaps an authorization code for a token via the token endpoint.

func LoadToken

func LoadToken(dir, provider string) (*Token, error)

LoadToken reads a previously saved token. Returns (nil, nil) if absent.

func Login

func Login(ctx context.Context, cfg LoginConfig) (*Token, error)

Login runs the full PKCE flow: starts a loopback server, opens the browser, waits for the callback, validates state, exchanges the code, and returns the resulting Token. Caller persists via SaveToken.

func RefreshToken

func RefreshToken(ctx context.Context, tokenURL, clientID, refreshToken string) (*Token, error)

RefreshToken swaps a refresh token for a new access token.

func (*Token) Expired

func (t *Token) Expired() bool

Expired returns true if the token has passed its expiration time (with a 5min safety skew). Tokens with ExpiresIn <= 0 are treated as non-expiring (provider didn't tell us).

Jump to

Keyboard shortcuts

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