siyuan-note/siyuan · error

OIDC claim [%s] is not allowed

Error message

OIDC claim [%s] is not allowed

What it means

AllowAll is false and at least one ClaimRules entry found no matching value among the user's ID-token claims. %s names the claim (e.g. email, groups) that failed every rule. This is authorization failure - the user authenticated successfully but is not permitted to use this SiYuan.

Source

Thrown at kernel/model/oidc.go:971

		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 251596fc0d)

Solutions

  1. Inspect the user's actual claims at the IdP and confirm the claim name and values.
  2. Adjust ClaimRules (operator and/or Values) to match real claim data, or grant the user the required claim value at the IdP.
  3. Set AllowAll only if you intentionally want to bypass claim-based authorization.

Example fix

// before
ClaimRules: [{Claim:"groups", Operator:"equals", Values:["staff"]}]
// user has group "contractors" and is rejected
// after - broaden allowed values
ClaimRules: [{Claim:"groups", Operator:"equals", Values:["staff","contractors"]}]
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check claim policy against a sample of the user's claims before requiring login.
func claimsSatisfy(config *conf.OIDC, claims map[string]any) error {
    if config.AllowAll {
        return nil
    }
    for _, rule := range config.ClaimRules {
        matched := false
        for _, v := range oidcClaimValues(claims[rule.Claim]) {
            for _, allowed := range rule.Values {
                if rule.Operator == conf.OidcClaimOperatorEquals && v == allowed {
                    matched = true
                } else if rule.Operator == conf.OidcClaimOperatorContains && strings.Contains(v, allowed) {
                    matched = true
                }
            }
        }
        if !matched {
            return fmt.Errorf("claim %s not satisfied", rule.Claim)
        }
    }
    return nil
}

Try / catch

// Map authorization failure to a 403 with the failing claim, not a 500.
if err := authorizeOIDCClaims(config, claims); err != nil && strings.Contains(err.Error(), "is not allowed") {
    respondForbidden(c, err.Error())
}

Prevention

When it happens

Trigger: A user authenticates at the IdP but their claims contain none of the allowed values for a configured rule; the configured claim name is not emitted by the IdP; the operator value does not match (e.g. wrong email domain).

Common situations: Rule expects groups:["staff"] but the user is not in staff; claim name typo in config; IdP does not emit the configured claim; email-domain contains rule with a wrong domain.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/f0171dc2db847b69. Report an issue: GitHub.