siyuan-note/siyuan · warning
OIDC claim [ ] is not allowed
Error message
OIDC claim [%s] is not allowed
What it means
authorizeOIDCClaims enforces admin-configured claim rules: for each rule, the ID token's claim values must match one of the allowed values (rules combined per AND semantics, as tested by TestAuthorizeOIDCClaimsCombinesRulesWithAnd). If a required claim's values contain none of the allowed entries, the token is rejected with this error naming the offending claim.
Solutions
- Add the user's actual claim value to the allowed values list in the OIDC auth settings, or remove/loosen the rule
- Verify the claim name against a real ID token (decode it at jwt.io) — check exact casing and nesting (e.g. 'roles' vs 'https://.../roles')
- Check the user's group/role assignment at the identity provider and have them re-login to get a fresh token
- Temporarily enable claim logging/debugging to see the token's claims and compare with configured rules
Example fix
// before
rule: {Claim: "groups", Values: ["admins"]} // user has ["developers"]
// after
rule: {Claim: "groups", Values: ["admins", "developers"]} Defensive patterns
Strategy: validation
Validate before calling
// decode the ID token client-side and check required claims before login
decoded := decodeJWT(idToken)
for _, rule := range configuredRules {
if !containsAny(toStringSlice(decoded[rule.Claim]), rule.Values) { return fmt.Errorf("claim %s not satisfied", rule.Claim) }
} Type guard
func claimAllowed(claims map[string]any, claim string, allowed []string) bool {
v, ok := claims[claim]
if !ok { return false }
for _, s := range oidcClaimValues(v) { for _, a := range allowed { if s == a { return true } } }
return false
} Try / catch
if err := model.OIDCCallback(c, code); err != nil && strings.Contains(err.Error(), "is not allowed") {
renderAuthError(c, "Your account does not have access: missing required attribute " + extractClaim(err))
} Prevention
- Copy claim names exactly from a real decoded ID token, including namespace prefixes
- Confirm user group/role assignment at the IdP before granting access expectations
- Keep the allowed-values list current when teams change
- Test rules with a test account from each access tier
When it happens
Trigger: A user whose ID token lacks one of the allowed values for a configured claim rule logs in or completes validation via finishOIDCExchange → authorizeOIDCClaims. E.g. rule claim=groups allowed=[admins] but the user's groups are [devs].
Common situations: User not assigned to the required group/role at the IdP; claim name typo in settings (e.g. 'Groups' vs 'groups'); IdP emits claim as a single string while rules expect a list (handled by oidcClaimValues) or vice versa; IdP omits the claim entirely for that user.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- decode OIDC claims failed
- 314
- 314
- A loopback OIDC redirect URL is required for local access
- A public HTTPS OIDC redirect URL is required for remote…
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/f0171dc2db847b69.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/oidc.go:911
matched := false
for _, claimValue := range claimValues {
for _, allowedValue := range rule.Values {
switch rule.Operator {
case conf.OIDCClaimOperatorEquals:
matched = claimValue == allowedValue
case conf.OIDCClaimOperatorContains:
matched = strings.Contains(claimValue, allowedValue)
}
if matched {
break
}
}
if matched {
break
}
}
if !matched {
return fmt.Errorf("OIDC claim [%s] is not allowed", rule.Claim)
}
}
return nil
}
func oidcClaimValues(value any) []string {
switch typed := value.(type) {
case string:
return []string{typed}
case bool, float64, float32, int, int64, json.Number:
return []string{fmt.Sprint(typed)}
case []string:
return typed
case []any:
ret := make([]string, 0, len(typed))
for _, item := range typed {
values := oidcClaimValues(item)
if len(values) == 1 {View on GitHub (pinned to 9f775e8a12)