Documentation
¶
Overview ¶
Package oauth is Cartograph's own OAuth 2.1 authorization server for agents (docs/adr/0016): the browser flow an MCP client starts, with no client registered anywhere beforehand. A client registers itself, by a Client ID Metadata Document or by dynamic registration; its person signs in as they always do, through whatever authenticates the deployment, and consents on a page here; the client gets a short-lived access token and a refresh token, both bound to an agent grant the engine keeps and its person or an administrator revokes.
It is one adapter of two. A deployment whose own stack is the authorization server (an identity provider behind a proxy, or Laravel Passport) leaves it out, and its proxy authenticates MCP requests as it does every other.
Nothing is kept here between requests: registrations, codes and tokens are signed with the deployment's key, and a grant's state is the engine's.
Index ¶
- Constants
- Variables
- type Authenticator
- type Grants
- type Options
- type Server
- func (s *Server) Authenticate(r *http.Request) (identity.Principal, error)
- func (s *Server) Handler() http.Handler
- func (s *Server) Mint(ctx context.Context, label string, ttl time.Duration) (string, store.AgentGrant, error)
- func (s *Server) Protect(next http.Handler, ...) http.Handler
- func (s *Server) Resource() string
Constants ¶
const MCPPath = "/api/v1/mcp"
MCPPath is where the protected resource is served.
const Scope = "cartograph"
Scope is the one scope there is: an agent acts for its person, under ADR 0016's ceiling, and no scope widens or narrows that.
Variables ¶
var ErrShortKey = errors.New("the agent signing key must be at least 32 bytes")
ErrShortKey is a signing key under 32 bytes.
var Routes = []string{ "/.well-known/oauth-authorization-server", "/.well-known/oauth-protected-resource", "/.well-known/oauth-protected-resource" + MCPPath, "/oauth/register", "/oauth/authorize", "/oauth/token", }
Routes are the paths Handler serves, for a mux to send there.
Functions ¶
This section is empty.
Types ¶
type Authenticator ¶
Authenticator says who is signing in at the consent page: the same authenticator as every other request.
type Grants ¶
type Grants interface {
Grants(ctx context.Context, p identity.Principal) (identity.Grants, error)
GrantAgent(ctx context.Context, label string, ttl time.Duration) (store.AgentGrant, error)
AgentGrantPrincipal(ctx context.Context, id string) (identity.Principal, store.AgentGrant, error)
AdvanceAgentGrant(ctx context.Context, id string, gen int) (int, error)
}
Grants is what this adapter needs of the engine: grants are recorded, resolved and advanced there, under its rules.
type Options ¶
type Options struct {
Grants Grants
// Person identifies the person at the consent page.
Person Authenticator
// Key signs registrations, codes and tokens: the same on every
// replica, at least 32 bytes.
Key []byte
// Issuer is this deployment's public address, such as
// https://cartograph.example.org, with no trailing slash.
Issuer string
// Fetch fetches Client ID Metadata Documents. nil is a client that
// refuses private and loopback addresses.
Fetch *http.Client
}
Options configures a Server.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the authorization server, and the authenticator for the tokens it issues.
func (*Server) Authenticate ¶
Authenticate is who an access token acts for: its grant's person, with the agent beside them. A request with no token, or a bad one, is refused.
func (*Server) Mint ¶
func (s *Server) Mint(ctx context.Context, label string, ttl time.Duration) (string, store.AgentGrant, error)
Mint lets an agent act for the signed-in person by a token they paste into its client, for a client that cannot sign in through the browser: an access token that lasts as long as its grant, and ends with it.
func (*Server) Protect ¶
func (s *Server) Protect(next http.Handler, onPrincipal func(*http.Request, identity.Principal) *http.Request) http.Handler
Protect authenticates every request to next by its access token, and answers one without a good token as MCP clients expect: 401, pointing at the protected resource metadata, where the browser flow starts.