template-monorepo/internal/library/actor/actor.go

46 lines
1.5 KiB
Go

// Package actor stores the calling user (tenant_id + uid) on a request
// context so middleware can inject it once and any downstream layer
// (handler / logic / usecase / repository) can read it without
// re-parsing the JWT.
//
// The package lives under internal/library because it is depended on
// by BOTH internal/middleware AND internal/logic/*. Defining the
// context key here is the only way to keep a single key value across
// packages (Go context.Value keys are typed by package, so each
// package would otherwise get its own isolated slot).
package actor
import (
"context"
"fmt"
)
type contextKey struct{}
// Actor identifies the calling tenant member, injected by the AuthJWT
// middleware after a successful Bearer token parse.
type Actor struct {
TenantID string
UID string
}
// WithActor stores tenant/uid on ctx. Returns the original ctx
// unchanged when either field is empty.
func WithActor(ctx context.Context, tenantID, uid string) context.Context {
if tenantID == "" || uid == "" {
return ctx
}
return context.WithValue(ctx, contextKey{}, Actor{TenantID: tenantID, UID: uid})
}
// ActorFromContext returns the actor injected by AuthJWT. The error is
// a plain error (no biz code) so callers can wrap it with their own
// scope-specific Builder when needed.
func ActorFromContext(ctx context.Context) (Actor, error) {
v, ok := ctx.Value(contextKey{}).(Actor)
if !ok || v.TenantID == "" || v.UID == "" {
return Actor{}, fmt.Errorf("missing bearer token or X-Tenant-ID/X-UID headers")
}
return v, nil
}