package authmw import ( "net/http" "code.nochebuena.dev/einherjar/contracts/logging" "code.nochebuena.dev/einherjar/contracts/security" "code.nochebuena.dev/einherjar/core/xerrors" "code.nochebuena.dev/einherjar/web/httputil" ) type enrichConfig struct { enrichers []BagEnricher } // EnrichmentMiddleware builds a [security.SecurityBag] from the uid and claims // injected by an upstream provider AuthMiddleware via [SetTokenData], then runs // all registered [BagEnricher] functions in order. // // Returns 401 if no uid is present in context; 500 if the application // [IdentityEnricher] returns an error. // // The resulting bag is stored via [security.SetBagInContext]. Downstream // handlers can retrieve it with [security.BagFromContext] (full bag) or // [security.FromContext] (Identity only). func EnrichmentMiddleware(logger logging.Logger, enricher IdentityEnricher, opts ...EnrichOpt) func(http.Handler) http.Handler { cfg := &enrichConfig{} for _, o := range opts { o(cfg) } return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { uid, ok := getUID(r.Context()) if !ok { httputil.Error(logger, w, r, xerrors.Unauthorized("missing token")) return } claims := getClaims(r.Context()) identity, err := enricher.Enrich(r.Context(), uid, claims) if err != nil { httputil.Error(logger, w, r, xerrors.Internal("enrichment failed").WithError(err)) return } bag := security.NewSecurityBag(identity) for _, fn := range cfg.enrichers { bag = fn(bag, r) } ctx := security.SetBagInContext(r.Context(), bag) next.ServeHTTP(w, r.WithContext(ctx)) }) } }