Documentation
¶
Index ¶
- Constants
- Variables
- func BexprMatchFunction() func(args ...any) (any, error)
- func CalculateExpiry(createdAt time.Time) time.Time
- func ClaimsFromContext(ctx context.Context) (map[string]any, bool)
- func EvaluateBexpr(scopeExpr string, labels map[string]any) bool
- func ExpandWildcard(action string) []string
- func ExtractClaimString(claims map[string]interface{}, claimField string) (string, error)
- func ExtractEmailFromClaims(claims map[string]interface{}, claimField string) (string, error)
- func ExtractGroupID(principal string) (string, error)
- func ExtractGroups(claims map[string]interface{}, claimField string, claimPath string) ([]string, error)
- func ExtractGroupsFromIDToken(idToken string) ([]string, error)
- func ExtractNameFromClaims(claims map[string]interface{}) string
- func ExtractRoleID(principal string) (string, error)
- func ExtractServiceAccountID(principal string) (string, error)
- func ExtractSubjectFromClaims(claims map[string]interface{}, claimField string) (string, error)
- func ExtractUserID(principal string) (string, error)
- func GenerateBearerToken() (string, string, error)
- func GenerateNonce() (string, error)
- func GetGroupsFromContext(ctx context.Context) []string
- func GetPrincipalType(principal string) string
- func GetRedirectURICookie(w http.ResponseWriter, r *http.Request) string
- func GroupID(name string) string
- func HashBearerToken(token string) string
- func HashToken(token string) string
- func InitEnforcer(db *bun.DB) (casbin.IEnforcer, error)
- func IsSessionExpired(expiresAt time.Time) bool
- func IsSessionRevoked(revoked bool) bool
- func JTIFromClaims(claims map[string]any) (string, bool)
- func NewVerifier(cfg *config.Config, opts ...VerifierOption) (func(http.Handler) http.Handler, error)
- func RoleID(name string) string
- func ServiceAccountID(id string) string
- func SetClaimsContext(ctx context.Context, claims map[string]any) context.Context
- func SetGroupsContext(ctx context.Context, groups []string) context.Context
- func SetRedirectURICookie(w http.ResponseWriter, r *http.Request, redirectURI string)
- func SetTokenHashContext(ctx context.Context, hash string) context.Context
- func SetUserContext(ctx context.Context, principal AuthenticatedPrincipal) context.Context
- func TerraformBasicAuthShim(next http.Handler) http.Handler
- func TokenHashFromContext(ctx context.Context) (string, bool)
- func TokenStringFromContext(ctx context.Context) (string, bool)
- func UserID(id string) string
- func ValidateAction(action string) bool
- func ValidateClaims(claims map[string]interface{}, requiredClaims []string) error
- func ValidateEmail(email string) error
- func ValidateSessionInfo(info *SessionInfo) error
- func ValidateSessionToken(expiresAt time.Time, revoked bool, identityDisabled bool) error
- func ValidateSubject(subject string) error
- type AuthenticatedPrincipal
- type ErrorResponder
- type PrincipalType
- type Provider
- type ProviderDependencies
- type RelyingParty
- type SessionInfo
- type Skipper
- type VerifierOption
Constants ¶
const ( // StateCreate allows creating new states StateCreate = "state:create" // StateRead allows reading state metadata StateRead = "state:read" // StateList allows listing states StateList = "state:list" // StateUpdateLabels allows updating state labels StateUpdateLabels = "state:update-labels" // StateDelete allows deleting states StateDelete = "state:delete" )
Control Plane Actions (state management)
const ( // TfstateRead allows reading Terraform state content TfstateRead = "tfstate:read" // TfstateWrite allows writing Terraform state content TfstateWrite = "tfstate:write" // TfstateLock allows locking a state TfstateLock = "tfstate:lock" // TfstateUnlock allows unlocking a state TfstateUnlock = "tfstate:unlock" )
Data Plane Actions (Terraform HTTP backend)
const ( // DependencyCreate allows creating dependencies DependencyCreate = "dependency:create" // DependencyRead allows reading dependency metadata DependencyRead = "dependency:read" // DependencyList allows listing dependencies for a specific state (state-scoped) DependencyList = "dependency:list" // DependencyListAll allows listing all edges in the system (globally allowed, filtered by handler) DependencyListAll = "dependency:list-all" // DependencyDelete allows deleting dependencies DependencyDelete = "dependency:delete" )
Dependency Actions
const ( // StateOutputList allows listing available output keys from a state StateOutputList = "state-output:list" // StateOutputRead allows reading specific output values from a state StateOutputRead = "state-output:read" // StateOutputSchemaWrite allows setting/updating JSON Schema for a state output StateOutputSchemaWrite = "state-output:schema-write" // StateOutputSchemaRead allows reading JSON Schema for a state output StateOutputSchemaRead = "state-output:schema-read" )
State Output Actions
const ( // PolicyRead allows reading label policy PolicyRead = "policy:read" // PolicyWrite allows updating label policy PolicyWrite = "policy:write" )
Policy Actions (label validation)
const ( // AdminRoleManage allows creating/updating/deleting roles AdminRoleManage = "admin:role-manage" // AdminUserAssign allows assigning/removing roles to/from users AdminUserAssign = "admin:user-assign" // AdminGroupAssign allows assigning/removing roles to/from groups AdminGroupAssign = "admin:group-assign" // AdminServiceAccountManage allows creating/revoking service accounts AdminServiceAccountManage = "admin:service-account-manage" // AdminSessionRevoke allows revoking sessions AdminSessionRevoke = "admin:session-revoke" // AdminCacheRefresh allows manually refreshing the group→role cache AdminCacheRefresh = "admin:cache-refresh" )
Admin Actions (RBAC management)
const ( // StateWildcard grants all state actions StateWildcard = "state:*" // TfstateWildcard grants all tfstate actions TfstateWildcard = "tfstate:*" // DependencyWildcard grants all dependency actions DependencyWildcard = "dependency:*" // StateOutputWildcard grants all state-output actions StateOutputWildcard = "state-output:*" // PolicyWildcard grants all policy actions PolicyWildcard = "policy:*" // AdminWildcard grants all admin actions AdminWildcard = "admin:*" // AllWildcard grants all actions (platform-engineer) AllWildcard = "*" )
Wildcard Actions (used in policies for broad access)
const ( // ObjectTypeState represents state resources ObjectTypeState = "state" // ObjectTypePolicy represents policy resources ObjectTypePolicy = "policy" // ObjectTypeAdmin represents administrative resources ObjectTypeAdmin = "admin" // ObjectTypeAll is a wildcard for all object types ObjectTypeAll = "*" )
Object Types for Casbin policies
const ( PrefixUser = "user:" PrefixGroup = "group:" PrefixServiceAccount = "sa:" PrefixRole = "role:" )
Prefix constants for Casbin identifiers These ensure consistent naming across user-role groupings, group-role mappings, and policy definitions
Reference: PREFIX-CONVENTIONS.md §2-3, §9 (helper function patterns)
const ( // SessionDuration is the default session lifetime (12 hours) SessionDuration = 12 * time.Hour // TokenLength is the length of generated bearer tokens in bytes TokenLength = 32 )
const ( // ReadSelf allows a principal to read their own data // This is a special action used in the Casbin model's ownership check // When r.act == "read-self" && r.sub == r.obj, access is granted ReadSelf = "read-self" )
Ownership Actions (self-service access)
const SessionCookieName = "grid.session"
const SystemUserID = "00000000-0000-0000-0000-000000000000"
SystemUserID is the well-known UUID for the system user, used for attributing actions performed by the system itself (e.g., database seeding, automated tasks).
Variables ¶
var ( // ErrOIDCDisabled is returned when OIDC configuration is incomplete. ErrOIDCDisabled = errors.New("oidc provider disabled") )
Functions ¶
func BexprMatchFunction ¶
BexprMatchFunction returns the bexprMatch function for Casbin This function evaluates go-bexpr expressions against resource labels
Reference: research.md §1 (lines 443-482)
func CalculateExpiry ¶
CalculateExpiry calculates session expiry time from creation Returns current time + SessionDuration (12 hours)
func ClaimsFromContext ¶
ClaimsFromContext returns the JWT claims stored on the request context.
func EvaluateBexpr ¶
EvaluateBexpr evaluates a go-bexpr expression against resource labels Empty scopeExpr returns true (no constraint) Caches compiled evaluators for performance
Reference: research.md §1 (lines 443-482)
func ExpandWildcard ¶
ExpandWildcard expands wildcard actions to their concrete actions Example: "state:*" → ["state:create", "state:read", "state:list", "state:update-labels", "state:delete"]
func ExtractClaimString ¶
ExtractClaimString extracts a string claim from JWT claims Generic helper for extracting string values from configurable claim fields
func ExtractEmailFromClaims ¶
ExtractEmailFromClaims extracts the email from JWT claims Uses configurable claim field (default: "email")
func ExtractGroupID ¶
ExtractGroupID extracts the group name from a Casbin principal identifier Returns the name without prefix, or error if prefix mismatch Example: ExtractGroupID("group:dev-team") → "dev-team", nil
func ExtractGroups ¶
func ExtractGroups(claims map[string]interface{}, claimField string, claimPath string) ([]string, error)
ExtractGroups handles both flat and nested group claims from JWT tokens Supports:
- Flat arrays: ["dev-team", "contractors"]
- Nested objects: [{"name": "dev-team", "type": "team"}] with claimPath="name"
Reference: research.md §9 (lines 629-787), CLARIFICATIONS.md §1 (JWT claim config)
func ExtractGroupsFromIDToken ¶
ExtractGroupsFromIDToken parses a JWT ID token and extracts the "groups" claim. The token is parsed without verification since it's already validated and stored in the database. Returns an empty slice if no groups claim is present.
This function is used by: - Session interceptor (to extract groups from stored ID token for external IdP users) - SSO callback handler (to extract groups during initial authentication)
Related: grid-80ad (External IdP group-to-role mapping fix)
func ExtractNameFromClaims ¶
ExtractNameFromClaims extracts the name from JWT claims (optional) Uses standard "name" claim field
func ExtractRoleID ¶
ExtractRoleID extracts the role name from a Casbin principal identifier Returns the name without prefix, or error if prefix mismatch Example: ExtractRoleID("role:product-engineer") → "product-engineer", nil
func ExtractServiceAccountID ¶
ExtractServiceAccountID extracts the service account ID from a Casbin principal identifier Returns the ID without prefix, or error if prefix mismatch Example: ExtractServiceAccountID("sa:550e8400-e29b-41d4-a716-446655440000") → "550e8400-e29b-41d4-a716-446655440000", nil
func ExtractSubjectFromClaims ¶
ExtractSubjectFromClaims extracts the user subject ID from JWT claims Uses configurable claim field (default: "sub")
func ExtractUserID ¶
ExtractUserID extracts the user ID from a Casbin principal identifier Returns the ID without prefix, or error if prefix mismatch Example: ExtractUserID("user:alice@example.com") → "alice@example.com", nil
func GenerateBearerToken ¶
GenerateBearerToken generates a cryptographically secure random bearer token Returns: token (hex string), token hash (SHA256 hex), error
Reference: FR-007 (session management), data-model.md §294-335 (Session entity)
func GenerateNonce ¶
GenerateNonce generates a random nonce string.
func GetGroupsFromContext ¶
GetGroupsFromContext retrieves the resolved group list from the context.
func GetPrincipalType ¶
GetPrincipalType returns the type of a Casbin principal (user, group, sa, role) Returns empty string if prefix not recognized
func GetRedirectURICookie ¶
func GetRedirectURICookie(w http.ResponseWriter, r *http.Request) string
GetRedirectURICookie retrieves and clears the redirect URI cookie. Returns empty string if cookie not found or expired. Related: Beads issue grid-202d (SSO callback redirect fix)
func GroupID ¶
GroupID creates a Casbin group identifier with the standard prefix Example: GroupID("dev-team") → "group:dev-team"
func HashBearerToken ¶
HashBearerToken hashes a bearer token for storage/lookup Returns SHA256 hex hash
func InitEnforcer ¶
InitEnforcer creates and initializes a Casbin enforcer with embedded model and database adapter Uses msales/casbin-bun-adapter to share the existing *bun.DB connection pool
Reference: research.md §1 (lines 429-490), §7 (adapter usage)
func IsSessionExpired ¶
IsSessionExpired checks if a session has expired
func IsSessionRevoked ¶
IsSessionRevoked checks session revocation flag
func JTIFromClaims ¶
JTIFromClaims extracts the JWT ID claim from the claims map. This is used for revocation checking in the authentication middleware.
func NewVerifier ¶
func NewVerifier(cfg *config.Config, opts ...VerifierOption) (func(http.Handler) http.Handler, error)
NewVerifier constructs a Chi-compatible middleware that validates JWTs using go-oidc-middleware.
func RoleID ¶
RoleID creates a Casbin role identifier with the standard prefix Example: RoleID("product-engineer") → "role:product-engineer"
func ServiceAccountID ¶
ServiceAccountID creates a Casbin service account identifier with the standard prefix Example: ServiceAccountID("550e8400-e29b-41d4-a716-446655440000") → "sa:550e8400-e29b-41d4-a716-446655440000"
func SetClaimsContext ¶
SetClaimsContext allows middleware to inject synthetic claims (e.g., from session cookies). This enables session authentication to reuse the existing JWT authentication flow.
func SetGroupsContext ¶
SetGroupsContext stores the resolved group list on the context.
func SetRedirectURICookie ¶
func SetRedirectURICookie(w http.ResponseWriter, r *http.Request, redirectURI string)
SetRedirectURICookie stores the redirect URI in a temporary cookie for the SSO flow. This cookie is short-lived (10 minutes) and used to remember where to redirect after OAuth callback. Related: Beads issue grid-202d (SSO callback redirect fix)
func SetTokenHashContext ¶
SetTokenHashContext allows middleware to set token hash for session lookup.
func SetUserContext ¶
func SetUserContext(ctx context.Context, principal AuthenticatedPrincipal) context.Context
SetUserContext stores the authenticated principal on the context for downstream consumers.
func TerraformBasicAuthShim ¶
TerraformBasicAuthShim rewrites Terraform's Basic Auth credential promotion into a standard Bearer token header. The password component of the decoded credential is treated as the bearer token and injected into the Authorization header so downstream middleware can operate on a canonical representation. Requests that already present a Bearer token are left untouched.
func TokenHashFromContext ¶
TokenHashFromContext returns the SHA256 hash of the bearer token extracted during verification.
func TokenStringFromContext ¶
TokenStringFromContext returns the raw bearer token extracted during verification.
func UserID ¶
UserID creates a Casbin user identifier with the standard prefix Example: UserID("alice@example.com") → "user:alice@example.com"
func ValidateAction ¶
ValidateAction checks if an action string is valid This prevents typos when creating/updating policies
func ValidateClaims ¶
ValidateClaims performs comprehensive validation of JWT claims Checks required fields, expiration, and claim formats
Reference: FR-006, FR-006a (token validation requirements)
func ValidateEmail ¶
ValidateEmail validates email format (basic RFC 5322 check)
func ValidateSessionInfo ¶
func ValidateSessionInfo(info *SessionInfo) error
ValidateSessionInfo validates session info before creation Ensures exactly one identity type is set
func ValidateSessionToken ¶
ValidateSessionToken performs comprehensive session validation Checks expiration, revocation, and identity status
Reference: FR-007 (session revocation), FR-070b (cascade revocation)
func ValidateSubject ¶
ValidateSubject validates the subject claim format Subject must be in format: provider|provider_user_id (e.g., "keycloak|123")
Reference: data-model.md §56 (User.Subject validation)
Types ¶
type AuthenticatedPrincipal ¶
type AuthenticatedPrincipal struct {
// Subject is the stable OIDC subject or client identifier (unprefixed).
Subject string
// PrincipalID is the Casbin-ready identifier (e.g., user:alice@example.com).
PrincipalID string
// InternalID references the backing database record (users.id or service_accounts.id).
InternalID string
// Email is optional and present for human users when available.
Email string
// Name is optional display name for human users.
Name string
// SessionID references the active session row when available.
SessionID string
// Roles lists effective Casbin role identifiers resolved during authentication.
Roles []string
// Type differentiates users and service accounts.
Type PrincipalType
}
AuthenticatedPrincipal captures identity metadata propagated through the request context.
func GetUserFromContext ¶
func GetUserFromContext(ctx context.Context) (AuthenticatedPrincipal, bool)
GetUserFromContext retrieves the authenticated principal from the context.
type ErrorResponder ¶
type ErrorResponder func(http.ResponseWriter, *http.Request, error)
ErrorResponder writes authentication failures to the response writer.
type PrincipalType ¶
type PrincipalType string
PrincipalType describes the type of authenticated principal.
const ( // PrincipalTypeUser represents a human user authenticated via OIDC. PrincipalTypeUser PrincipalType = "user" // PrincipalTypeServiceAccount represents a non-interactive service account. PrincipalTypeServiceAccount PrincipalType = "service_account" )
type Provider ¶
Provider exposes the server-side OIDC endpoints wired through zitadel/oidc.
func NewOIDCProvider ¶
func NewOIDCProvider(ctx context.Context, cfg config.OIDCConfig, deps ProviderDependencies) (*Provider, error)
NewOIDCProvider builds an OpenID provider instance when OIDC is enabled.
type ProviderDependencies ¶
type ProviderDependencies struct {
Users repository.UserRepository
ServiceAccounts repository.ServiceAccountRepository
Sessions repository.SessionRepository
}
ProviderDependencies holds the repositories required by the OIDC storage adapter.
type RelyingParty ¶
type RelyingParty struct {
// contains filtered or unexported fields
}
RelyingParty handles OIDC authentication against an external IdP by wrapping the zitadel/oidc RelyingParty implementation.
func NewRelyingParty ¶
func NewRelyingParty(ctx context.Context, cfg *config.ExternalIdPConfig) (*RelyingParty, error)
NewRelyingParty creates a new RelyingParty for external IdP authentication.
func (*RelyingParty) RP ¶
func (r *RelyingParty) RP() rp.RelyingParty
RP returns the underlying zitadel/oidc RelyingParty interface.
type SessionInfo ¶
type SessionInfo struct {
UserID *string // Set for human users
ServiceAccountID *string // Set for service accounts
IDToken string // OIDC ID token (JWT) for human sessions
RefreshToken string // OIDC refresh token (optional)
UserAgent string // Browser/CLI user agent
IPAddress string // Client IP address
}
SessionInfo represents session metadata for creation
type VerifierOption ¶
type VerifierOption func(*verifierOptions)
VerifierOption customises the behaviour of the OIDC verifier middleware.
func WithErrorResponder ¶
func WithErrorResponder(responder ErrorResponder) VerifierOption
WithErrorResponder overrides the default error responder used by the verifier.
func WithSkipper ¶
func WithSkipper(skipper Skipper) VerifierOption
WithSkipper overrides the default skipper used by the verifier.
func WithTokenString ¶
func WithTokenString(header, prefix string) VerifierOption
WithTokenString configures an alternate header and prefix that should be treated as a bearer token.
func WithTokenStringOptions ¶
func WithTokenStringOptions(setters ...options.TokenStringOption) VerifierOption
WithTokenStringOptions appends a token extraction strategy used by the verifier. The provided setters mirror go-oidc-middleware's token string configuration helpers.