HTTP Basic
Same shape as the API key example, but with username:password decoded by the runtime and a realm advertised on the failure response.
Spec
Wiring
api := untyped.NewAPI(doc).WithJSONDefaults()
api.RegisterAuth("basicAuth", security.BasicAuthRealmCtx(
"petstore",
func(ctx context.Context, user, pass string) (context.Context, any, error) {
// request-scoped lookup — honours ctx cancellation
principal, err := store.AuthenticateBasic(ctx, user, pass)
if err != nil {
return ctx, nil, errors.Unauthenticated("basic")
}
return ctx, principal, nil
},
))Full source: docs/examples/auth/basic/main.go
BasicAuthRealmCtx is the context-aware variant of BasicAuthRealm;
the non-*Ctx form
security.BasicAuthRealm("petstore", fn)
takes a func(user, pass string) (any, error) instead.
Replying with WWW-Authenticate on 401
The runtime stashes the realm name in the request context when basic auth has been attempted and failed. Recover it from a custom error handler to render a proper challenge:
api.ServeError = func(w http.ResponseWriter, r *http.Request, err error) {
if realm := security.FailedBasicAuthCtx(r.Context()); realm != "" {
w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`)
}
errors.ServeError(w, r, err)
}Full source: docs/examples/auth/basic/main.go
FailedBasicAuth(r) is the non-context spelling.
Exercise
When to combine with other schemes
Basic + Bearer is a common “either credential works” requirement. That’s the AND/OR composition case — see composed for how to declare and wire it.