authz

package
v1.11.0 Latest Latest
Warning

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

Go to latest
Published: Jul 22, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

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

Constants

This section is empty.

Variables

View Source
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 Challenge

func Challenge(metadataURL string, err error, requiredScopes []string) string

Challenge constructs a Bearer challenge without token-derived text.

func Drivers

func Drivers() []string

Drivers returns registered driver names in deterministic order.

func ParseBearer

func ParseBearer(values []string) (string, error)

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

func RawTokenFromContext(ctx context.Context) (string, bool)

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

func RegisterDriver(name string, factory Factory)

RegisterDriver registers a process-wide validator driver. Duplicate or invalid registrations panic because they are programming errors at startup.

func RequireScopes

func RequireScopes(p Principal, required ...string) error

RequireScopes requires every listed scope and returns the missing scopes.

func WithPrincipal

func WithPrincipal(ctx context.Context, p Principal) context.Context

WithPrincipal returns a child context containing a defensive copy of p.

func WithRawToken added in v1.10.0

func WithRawToken(ctx context.Context, token string) context.Context

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

func WithoutRawToken(ctx context.Context) context.Context

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

func (c Config) MetadataHandler() http.Handler

MetadataHandler serves immutable RFC 9728 metadata.

func (Config) MetadataURL

func (c Config) MetadataURL() (string, error)

MetadataURL returns the RFC 9728 path-aware well-known URL. A resource path is appended after /.well-known/oauth-protected-resource.

func (Config) Validate

func (c Config) Validate() error

Validate checks transport-independent protected-resource configuration.

type Factory

type Factory func(context.Context, Config) (Validator, error)

Factory constructs a validator for a validated Config.

type Principal

type Principal struct {
	Issuer   string
	Subject  string
	Resource string
	Scopes   []string
}

Principal is identity established by a Validator. Scopes is always copied at context boundaries so callers cannot mutate another component's identity.

func PrincipalFromContext

func PrincipalFromContext(ctx context.Context) (Principal, bool)

PrincipalFromContext returns a defensive copy of the verified principal.

func (Principal) BindingKey

func (p Principal) BindingKey() string

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.

type Validator

type Validator interface {
	Validate(context.Context, string) (Principal, error)
}

Validator validates an unadorned bearer token and never retains it.

func Open

func Open(ctx context.Context, cfg Config) (Validator, error)

Open validates cfg and constructs its validator.

Directories

Path Synopsis
Package jwtjwks implements signed JWT validation using RFC 8414 discovery and a bounded JWKS cache.
Package jwtjwks implements signed JWT validation using RFC 8414 discovery and a bounded JWKS cache.

Jump to

Keyboard shortcuts

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