// Package auth carries the authenticated caller through the request context. // // Every tenant-scoped query in this service takes its tenant id from the // Identity stored here, never from anything the client can name directly in a // query string or body. That is the single rule that keeps tenants isolated. package auth import ( "context" "errors" "github.com/travelswitch/travelhub/backend/internal/models" ) // Identity is the authenticated user together with the tenant they signed into. type Identity struct { User models.User Tenant models.Tenant } // contextKey is unexported so no other package can collide with our key. type contextKey struct{} var identityKey contextKey // ErrNoIdentity means the handler ran without authentication middleware in // front of it, which is a programming error rather than a client error. var ErrNoIdentity = errors.New("no identity in request context") // WithIdentity returns a context carrying the identity. func WithIdentity(ctx context.Context, id Identity) context.Context { return context.WithValue(ctx, identityKey, id) } // FromContext retrieves the identity placed by the auth middleware. func FromContext(ctx context.Context) (Identity, error) { id, ok := ctx.Value(identityKey).(Identity) if !ok { return Identity{}, ErrNoIdentity } return id, nil } // IsAdmin reports whether the caller holds the tenant admin role. func (i Identity) IsAdmin() bool { return i.User.Role == "admin" }