Purpose-scoped OAuth artifacts, each a macaroon (OAuthMCPBridge.Macaroon) —
fully stateless, so nothing is lost across scale-to-zero restarts and there is
no database or volume.
The structured payload lives in the (integrity-protected) macaroon identifier;
two caveats carry policy: purpose=<p> and exp=<unix>. A holder may attenuate
by appending a tighter exp= caveat (the soonest bound wins, since every caveat
must hold). Any caveat the verifier doesn't recognize fails closed, so
attenuation can only ever narrow authority.
:client— dynamic-registration client_id →%{"uris" => [...], "name" => ...}:state— GitHub-leg context → client_id, redirect_uri, PKCE, client state:code— our authorization code → client + PKCE + resolved login:access— the MCP bearer token →%{"sub" => login}:refresh— long-lived renewal credential →%{"sub" => login}; lets a client silently mint a new:accesstoken without a GitHub round-trip (OAuth 2.1 practice: short access-token TTL + refresh token, rather than one long-lived access token). Being stateless, a refresh isn't re-checked against the whitelist/org membership — it trusts thesubthe original code exchange already verified — so tightening the whitelist doesn't revoke an outstanding refresh token before its ownexp.
The root key is read at runtime from :persistent_term
({:oauth_mcp_bridge, :token_secret}) — set this before starting, e.g. in
your Application.start/2.
Summary
Functions
Access-token lifetime (seconds) for the expires_in field.
Mint a bearer string for purpose carrying payload.
Verify signature + purpose + expiry; return the payload map.
Functions
Access-token lifetime (seconds) for the expires_in field.
Mint a bearer string for purpose carrying payload.
Verify signature + purpose + expiry; return the payload map.