Files
rbac/identity.go

56 lines
1.8 KiB
Go
Raw Normal View History

package rbac
import "context"
// Identity represents the authenticated principal for a request.
//
// It is a value type — always copied, never a pointer — to prevent nil-check
// burden and avoid accidental mutation of a shared context value.
//
// Construction follows a two-step pattern:
// 1. [NewIdentity] populates authentication data from the token (uid, name, email).
// 2. [Identity.WithTenant] optionally enriches with a tenant ID in a later
// middleware step, returning a new value without mutating the original.
type Identity struct {
UID string
TenantID string
DisplayName string
Email string
}
// authContextKey is an unexported type used as the context key for Identity.
// Using a private type prevents collisions with keys from other packages.
type authContextKey struct{}
var authKey = authContextKey{}
// NewIdentity creates an Identity from token authentication data.
// TenantID is intentionally left empty — populate it later with [Identity.WithTenant]
// once the enrichment middleware has resolved it.
func NewIdentity(uid, displayName, email string) Identity {
return Identity{
UID: uid,
DisplayName: displayName,
Email: email,
}
}
// WithTenant returns a copy of the Identity with TenantID set to id.
// The receiver is not mutated — safe to call from concurrent middleware.
func (i Identity) WithTenant(id string) Identity {
i.TenantID = id
return i
}
// SetInContext stores the Identity in ctx and returns the enriched context.
func SetInContext(ctx context.Context, id Identity) context.Context {
return context.WithValue(ctx, authKey, id)
}
// FromContext retrieves the Identity stored by [SetInContext].
// Returns the zero-value Identity and false if no identity is present.
func FromContext(ctx context.Context) (Identity, bool) {
id, ok := ctx.Value(authKey).(Identity)
return id, ok
}