Tier: Platform · Status: Full · Java original: Spring Security · .NET project:
Microsoft.AspNetCore.Authentication.JwtBearer
security is the framework's HTTP-layer authentication and
authorization tier:
Verifier— port for token validators (any IDP adapter satisfies it).BearerMiddleware— extractsAuthorization: Bearer <token>, calls theVerifier, stores the resultingAuthenticationon the request context.FilterChain— path-pattern-keyed RBAC matcher composable with the bearer middleware.Authentication— principal + authorities tuple persisted on the context for downstream handlers and CQRS handlers alike.
incoming request
│
▼
┌──────────────────────────────────────┐
│ BearerMiddleware │
│ • reads Authorization: Bearer <tok> │
│ • calls Verifier (idp adapter) │
│ • stores Authentication on ctx │
│ • 401 application/problem+json on err│
└──────────────────────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ FilterChain.Middleware() │
│ Permit(prefix) → public │
│ Require(prefix, roles...) → RBAC │
│ 401 / 403 problem+json on miss │
└──────────────────────────────────────┘
│
▼
your handlers
(read MustAuthFrom(ctx))
type Authentication struct {
Principal string // unique stable id (sub claim)
Username string
Roles []string
Claims map[string]any
}
func (Authentication) HasRole(string) bool
func (Authentication) HasAnyRole(...string) bool
const AnonymousID = "anonymous"
type Verifier interface {
Verify(ctx, token string) (Authentication, error)
}
type VerifierFunc func(ctx, token string) (Authentication, error)
var ErrUnauthenticated = errors.New("…unauthenticated")
var ErrForbidden = errors.New("…forbidden")
func WithAuthentication(ctx, Authentication) context.Context
func AuthenticationFrom(ctx) (Authentication, bool)
func MustAuthFrom(ctx) Authentication
type BearerConfig struct {
Verifier Verifier
AllowAnonymous bool
HeaderName string
UnauthorizedFunc func(http.ResponseWriter, *http.Request, error)
}
func BearerMiddleware(BearerConfig) func(http.Handler) http.Handler
type FilterChain struct{ ... }
func NewFilterChain() *FilterChain
func (*FilterChain) Permit(prefix) *FilterChain
func (*FilterChain) PermitMethod(method, prefix) *FilterChain
func (*FilterChain) Require(prefix, roles...) *FilterChain
func (*FilterChain) Middleware() func(http.Handler) http.Handleridp.Adapter exposes Validate(ctx, accessToken) (User, error).
Adapt it to a security.Verifier:
verifier := security.VerifierFunc(func(ctx context.Context, token string) (security.Authentication, error) {
u, err := idpAdapter.Validate(ctx, token)
if err != nil { return security.Authentication{}, err }
return security.Authentication{
Principal: u.ID,
Username: u.Username,
Roles: u.Roles,
}, nil
})chain := security.NewFilterChain().
Permit("/actuator/health").
Permit("/actuator/info").
Require("/admin/", "ADMIN").
Require("/api/", "USER", "ADMIN")
mux := http.NewServeMux()
// … register routes …
bearer := security.BearerMiddleware(security.BearerConfig{Verifier: verifier})
http.ListenAndServe(":8080", bearer(chain.Middleware()(mux)))In handlers:
auth := security.MustAuthFrom(r.Context())
if !auth.HasAnyRole("ADMIN", "OPERATOR") {
web.WriteProblem(w, kernel.ProblemForbidden("must be admin/operator"))
return
}cd security
go test ./...Covers happy-path token verification, malformed-header 401, the
anonymous fallthrough mode, and the filter-chain permit / require / forbidden matrix.