Package bearer
Overview
Package bearer protects an API as an OAuth resource server: it takes bearer access tokens (RFC 6750), verifies them with an operation, and answers a request without a good token with the challenge that tells a client where to sign in (RFC 9728). It also serves the protected resource metadata that challenge points to.
It doesn't verify tokens itself. A VerifyTokenOpFunc does, such as the one funnyhaha.technology/httpkit/jwks builds, or a stub in tests:
challenge, metadataURL, err := bearer.NewChallenge("mcp", resource)
protect := bearer.New(verify, challenge).WithScope("public:read").Middleware()
mux.Handle("GET "+metadataPath, bearer.NewMetadata(metadata).Handler())
mux.Handle("/mcp", protect(mcpHandler))A handler behind the middleware reads the token's claims with ClaimsFrom.
Index
- Constants
- Variables
func ClaimsFromfunc MetadataPathfunc NewChallengefunc SubjectKeyfunc WithClaimstype Buildertype MetadataBuildertype VerifyTokenOpFunctype VerifyTokenParamstype VerifyTokenResult
Constants
const (
// DefaultRetryAfter is the Retry-After sent with a 503 when the keys
// that verify tokens can't be fetched.
DefaultRetryAfter = 30 * time.Second
// DefaultMetadataMaxAge is how long clients may cache the protected
// resource metadata.
DefaultMetadataMaxAge = time.Hour
)Defaults, used unless a With method changes them.
Variables
var (
// ErrInvalidToken is returned by a VerifyTokenOpFunc for a token that's
// expired, revoked, malformed, not for this resource or otherwise
// unacceptable. The middleware answers it with 401 and invalid_token.
ErrInvalidToken = errors.New("invalid token")
// ErrUnavailable is returned by a VerifyTokenOpFunc that can't decide,
// because what it verifies with, such as the authorization server's
// keys, can't be fetched. The middleware answers it with 503.
= errors.New("token verification unavailable")
// ErrNoClaims is returned by [SubjectKey] for a request without a
// verified token's subject.
ErrNoClaims = errors.New("no verified token subject")
)Functions
ClaimsFrom source
func ClaimsFrom(ctx context.Context) (rfc9068.Claims, bool)ClaimsFrom returns the claims of the request's verified token, and false if the request didn't pass through the middleware.
MetadataPath source
func MetadataPath(metadataURL string) (string, error)MetadataPath returns the path of a metadata URL, such as "/.well-known/oauth-protected-resource/mcp", for routing.
NewChallenge source
func NewChallenge(realm, resource string) (rfc6750.Challenge, string, error)NewChallenge returns the Bearer challenge for a resource, with the realm and a resource_metadata parameter pointing at the resource's protected resource metadata, and that metadata's URL (RFC 9728, Sections 3.1 and 5.1). Serve the metadata at the URL's path with NewMetadata.
SubjectKey source
func SubjectKey(r *http.Request) (string, error)SubjectKey returns the sub claim of the request's verified token, for rate limiting per subject (funnyhaha.technology/httpkit/ratelimit) behind the middleware. It returns ErrNoClaims for a request that didn't pass through the middleware, rather than counting every request under one key.
WithClaims source
func WithClaims(ctx context.Context, c rfc9068.Claims) context.ContextWithClaims returns a copy of ctx carrying a verified token's claims. The middleware calls it; tests of handlers behind it can too.
Types
Builder source
type Builder struct {
// contains filtered or unexported fields
}Builder configures the middleware. Its With methods return a modified copy.
New source
func New(verify VerifyTokenOpFunc, challenge rfc6750.Challenge) BuilderNew returns a builder for middleware that lets a request through only with a bearer token that verify accepts. The challenge is sent with every 401 and 403, so build it with NewChallenge to point clients at the metadata. It panics if verify is nil.
(Builder) Middleware source
func (b Builder) Middleware() func(http.Handler) http.HandlerMiddleware returns the middleware. A request
- without bearer credentials gets 401 with the challenge, and no error code (RFC 6750, Section 3.1);
- with a malformed token, or one the operation refuses with ErrInvalidToken, gets 401 with invalid_token;
- with a token that lacks a required scope gets 403 with insufficient_scope;
- whose token can't be verified, because of ErrUnavailable, gets 503 with Retry-After, and any other error gets 500.
Each error response is a problem (RFC 9457). The reason a token was refused goes to the request log, as auth_refused, and the token never does. A request with a good token proceeds, with its claims in the context for ClaimsFrom.
(Builder) WithRetryAfter source
func (b Builder) WithRetryAfter(d time.Duration) BuilderWithRetryAfter returns a copy of b that sends Retry-After: d with a 503.
(Builder) WithScope source
func (b Builder) WithScope(s rfc6750.Scope, more ...rfc6750.Scope) BuilderWithScope returns a copy of b that requires every request's token to have the scopes, as well as any required already. A token without one gets 403 with insufficient_scope, and every challenge lists the scopes, so a client knows what to ask for.
MetadataBuilder source
type MetadataBuilder struct {
// contains filtered or unexported fields
}MetadataBuilder configures the protected resource metadata handler. Its With methods return a modified copy.
NewMetadata source
func NewMetadata(m rfc9728.Metadata) MetadataBuilderNewMetadata returns a builder for a handler that serves m as protected resource metadata (RFC 9728, Section 3.2). It panics if m has no Resource, which Section 2 requires.
(MetadataBuilder) Handler source
func (b MetadataBuilder) Handler() http.HandlerHandler returns the handler. The document is marshalled once, here, so it panics if the metadata can't be. Cross-origin requests are the caller's to allow, with CORS middleware.
(MetadataBuilder) WithMaxAge source
func (b MetadataBuilder) WithMaxAge(d time.Duration) MetadataBuilderWithMaxAge returns a copy of b whose responses clients may cache for d.
VerifyTokenOpFunc source
type VerifyTokenOpFunc func(context.Context, VerifyTokenParams) (VerifyTokenResult, error)VerifyTokenOpFunc verifies an access token and returns its claims. It returns an error wrapping ErrInvalidToken for a token that mustn't be accepted, and ErrUnavailable when it can't tell.
VerifyTokenParams source
type VerifyTokenParams struct {
Token rfc6750.Token
}VerifyTokenParams holds the token to verify.
VerifyTokenResult source
type VerifyTokenResult struct {
Claims rfc9068.Claims
}VerifyTokenResult holds a verified token's claims.