auth/oidc: support slice-typed extra claims via overlap match (#1238)

Closes #988. Direct `actualValue != expectedValue` fails when the token
claim is an array (groups, roles, scp, aud). Switch to a slice-aware
any-of overlap so OIDC list claims are validated correctly.
This commit is contained in:
Sai Asish Y 2026-05-04 03:24:34 -07:00 • committed by GitHub
commit 811046c4ce
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -224,7 +224,7 @@ func (h *OIDCHandler) validateExtraClaims(claims *OIDCClaims) error {
return fmt.Errorf("claim validation failed: required claim %s not found", key)
}
if actualValue != expectedValue {
if !claimMatches(actualValue, expectedValue) {
return fmt.Errorf("claim validation failed: %s expected %v, got %v", key, expectedValue, actualValue)
}
}
@ -233,6 +233,38 @@ func (h *OIDCHandler) validateExtraClaims(claims *OIDCClaims) error {
return nil
}
// claimMatches reports whether a claim value satisfies the expected configuration.
// Both sides may be a scalar or a slice; for slice-typed claims (groups, roles, scp,
// aud, etc.) any single overlap is treated as a match, mirroring how OIDC consumers
// normally interpret list claims.
func claimMatches(actual, expected any) bool {
actualList := toAnySlice(actual)
expectedList := toAnySlice(expected)
for _, e := range expectedList {
for _, a := range actualList {
if a == e {
return true
}
}
}
return false
}
func toAnySlice(v any) []any {
switch s := v.(type) {
case []any:
return s
case []string:
out := make([]any, len(s))
for i, x := range s {
out[i] = x
}
return out
default:
return []any{v}
}
}
// buildPermissions builds permissions based on OIDC claims and configuration
func (h *OIDCHandler) buildPermissions(_ *OIDCClaims) []auth.Permission {
var permissions []auth.Permission