Documentation
¶
Overview ¶
Package authz provides the transport-independent authorization foundation for Dockyard protected resources. HTTP integration supplies a bearer token to a Validator and places the resulting Principal in the request context.
Index ¶
- Variables
- func Challenge(metadataURL string, err error, requiredScopes []string) string
- func Drivers() []string
- func ParseBearer(values []string) (string, error)
- func RawTokenFromContext(ctx context.Context) (string, bool)
- func RegisterDriver(name string, factory Factory)
- func RequireScopes(p Principal, required ...string) error
- func WithPrincipal(ctx context.Context, p Principal) context.Context
- func WithRawToken(ctx context.Context, token string) context.Context
- func WithoutRawToken(ctx context.Context) context.Context
- type Config
- type Factory
- type Principal
- type ProtectedResourceMetadata
- type Validator
Constants ¶
This section is empty.
Variables ¶
var ( // ErrMissingToken indicates that no bearer token was supplied. ErrMissingToken = errors.New("authz: bearer token missing") // ErrInvalidToken indicates that a bearer token is malformed or failed validation. ErrInvalidToken = errors.New("authz: invalid token") // ErrInsufficientScope indicates that the principal lacks a required scope. ErrInsufficientScope = errors.New("authz: insufficient scope") )
Functions ¶
func Drivers ¶
func Drivers() []string
Drivers returns registered driver names in deterministic order.
func ParseBearer ¶
ParseBearer strictly accepts exactly one Authorization value containing the case-insensitive Bearer scheme, one SP, and a non-empty token68 value.
func RawTokenFromContext ¶ added in v1.10.0
RawTokenFromContext returns the validated inbound bearer token when the server was configured with ExposeRawToken. The false result — no token available — is the normal case; expose the token only to present it as an RFC 8693 subject_token to a trusted token-exchange endpoint (never log, persist, or forward it elsewhere).
func RegisterDriver ¶
RegisterDriver registers a process-wide validator driver. Duplicate or invalid registrations panic because they are programming errors at startup.
func RequireScopes ¶
RequireScopes requires every listed scope and returns the missing scopes.
func WithPrincipal ¶
WithPrincipal returns a child context containing a defensive copy of p.
func WithRawToken ¶ added in v1.10.0
WithRawToken returns a child context carrying the validated inbound bearer token. Framework-internal: the server sets it only when Config.ExposeRawToken is true, and only after the token has passed every validation gate (D-201).
func WithoutRawToken ¶ added in v1.10.0
WithoutRawToken returns a child context in which the exposed token reads as absent. It keeps the delegation token request-scoped: work detached from the originating request (e.g. an async Task run) must not inherit it — such work re-exchanges on its own fresh inbound token. Registered as a Tasks detach-scrubber by runtime/server so the strip is automatic.
Types ¶
type Config ¶
type Config struct {
Driver string
Resource string
Issuer string
// Scopes are advertised as supported in protected-resource metadata. Each
// value must be a non-empty RFC 6749 scope-token other than offline_access.
Scopes []string
// RequiredScopes are required on every protected MCP operation and follow
// the same syntax restrictions as Scopes.
RequiredScopes []string
DriverConfig any
// ContinuationKey authenticates framework-owned MRTR continuation state.
// It must contain at least 32 bytes and is never exposed on the wire.
ContinuationKey []byte
// ExposeRawToken makes the validated inbound bearer token retrievable from
// the handler context via RawTokenFromContext, for the sole purpose of
// presenting it as an RFC 8693 subject_token to a trusted token-exchange
// endpoint. Default false: the token is discarded after validation (D-201).
//
// Enable only when the server performs delegated token exchange. The token
// is exposed ONLY after full validation (signature, issuer, resource,
// subject, required scopes). It is request-scoped, never persisted, never
// placed in durable Task or MRTR continuation state, and must never be
// logged or forwarded to any endpoint other than the trusted exchange.
ExposeRawToken bool
// UnauthenticatedHandshake serves the MCP lifecycle and discovery methods
// WITHOUT requiring a token, and requires a valid token only on invocation
// methods. The exempt set is a Dockyard-owned, deny-by-default allowlist —
// lifecycle (initialize, notifications/initialized, ping, server/discover)
// and discovery (tools/list, resources/list, resources/templates/list,
// prompts/list), plus the transport-lifecycle GET (SSE stream-open) and
// DELETE (session teardown). Every other method — tools/call, resources/read,
// resources/subscribe, resources/unsubscribe, prompts/get, completion/complete,
// logging/setLevel, tasks/*, any notification other than initialized, and any
// unknown or future method — still requires a valid token (deny-by-default),
// so an invocation can never be accidentally exposed. Default false: every
// method is protected (the current behavior).
//
// A token presented on an exempt method is still validated for identity
// (signature, issuer, resource, subject) and its principal populated (so
// tools/list can be identity-filtered); RequiredScopes are NOT enforced on an
// exempt method (they gate invocation, not discovery), a token's ABSENCE is
// not an error, and an invalid token is still rejected. Invocation methods
// missing a valid token receive 401 + the Bearer challenge exactly as today.
// A JSON-RPC batch is exempt only when every element is an exempt method; any
// invocation element requires a valid token for the whole batch.
//
// This is the Stowage/D-152 posture: discovery is public, invocation is
// protected. It makes tool names, schemas, and descriptions discoverable
// without a token — the intended trade for a multi-user runtime that opens
// one shared connection and only holds a per-user token at tool-call time
// (D-202). Off by default; existing servers are unaffected.
UnauthenticatedHandshake bool
}
Config is the authorization configuration consumed by HTTP server options. Resource and Issuer must be canonical HTTPS URLs. Scope values must satisfy RFC 6749's scope-token grammar; offline_access is rejected because Dockyard is a resource server and does not issue refresh tokens. DriverConfig is interpreted only by the selected driver.
func (Config) Metadata ¶
func (c Config) Metadata() ProtectedResourceMetadata
Metadata returns defensively copied RFC 9728 handler data.
func (Config) MetadataHandler ¶
MetadataHandler serves immutable RFC 9728 metadata.
func (Config) MetadataURL ¶
MetadataURL returns the RFC 9728 path-aware well-known URL. A resource path is appended after /.well-known/oauth-protected-resource.
type Principal ¶
Principal is identity established by a Validator. Scopes is always copied at context boundaries so callers cannot mutate another component's identity.
func PrincipalFromContext ¶
PrincipalFromContext returns a defensive copy of the verified principal.
func (Principal) BindingKey ¶
BindingKey returns a stable, non-reversible identity suitable for persistence. Length-prefixing prevents tuple ambiguity; SHA-256 makes collisions computationally infeasible without requiring a deployment secret.
type ProtectedResourceMetadata ¶
type ProtectedResourceMetadata struct {
Resource string `json:"resource"`
AuthorizationServers []string `json:"authorization_servers"`
ScopesSupported []string `json:"scopes_supported,omitempty"`
BearerMethodsSupported []string `json:"bearer_methods_supported"`
}
ProtectedResourceMetadata is the RFC 9728 response shape used by Dockyard.