cloudflare/cloudflared · error
token has non-cloudflare issuer of %s: %s
Error message
token has non-cloudflare issuer of %s: %s
What it means
After verifying the JWT's signature, Validate checks that the token's issuer ends with 'cloudflareaccess.com'. A validly-signed token issued by something other than Cloudflare Access is rejected — usually a misconfiguration where the application AUD/issuer domain doesn't match the token's actual Access team.
Source
Thrown at validation/validation.go:208
keySet := oidc.NewRemoteKeySet(ctx, domainURL+accessCertPath)
return &Access{oidc.NewVerifier(issuerURL, keySet, &oidc.Config{ClientID: applicationAUD})}, nil
}
func (a *Access) Validate(ctx context.Context, jwt string) error {
token, err := a.verifier.Verify(ctx, jwt)
if err != nil {
return errors.Wrapf(err, "token is invalid: %s", jwt)
}
// Perform extra sanity checks, just to be safe.
if token == nil {
return fmt.Errorf("token is nil: %s", jwt)
}
if !strings.HasSuffix(token.Issuer, accessDomain) {
return fmt.Errorf("token has non-cloudflare issuer of %s: %s", token.Issuer, jwt)
}
return nil
}
func (a *Access) ValidateRequest(ctx context.Context, r *http.Request) error {
return a.Validate(ctx, r.Header.Get(accessJwtHeader))
}
View on GitHub (pinned to 2253eeeb25)
Solutions
- Confirm the JWT's iss claim (decode the token payload) and configure NewAccessValidator with that team's exact domain/issuer
- Ensure the request actually came through the Cloudflare Access deployment for this team, not another team or a direct origin hit
- Check the application AUD passed to NewAccessValidator matches this Access application
- Reject or log the offending token source — something is injecting non-Access JWTs into the header
Example fix
// before validator, err := validation.NewAccessValidator(ctx, "old-team.cloudflareaccess.com", "https://old-team.cloudflareaccess.com", aud) // after — match the team that actually issues the tokens validator, err := validation.NewAccessValidator(ctx, "myteam.cloudflareaccess.com", "https://myteam.cloudflareaccess.com", aud)
Defensive patterns
Strategy: validation
Validate before calling
func issuerIsCloudflare(jwt string) bool {
parts := strings.Split(jwt, ".")
if len(parts) != 3 { return false }
var claims struct{ Iss string `json:"iss"` }
raw, _ := base64.RawURLEncoding.DecodeString(parts[1])
_ = json.Unmarshal(raw, &claims)
return strings.HasSuffix(claims.Iss, "cloudflareaccess.com")
} Try / catch
if err := validator.Validate(ctx, jwt); err != nil {
if strings.Contains(err.Error(), "non-cloudflare issuer") {
log.Warn().Msg("token from wrong Access team or foreign OIDC provider")
}
http.Error(w, "Unauthorized", http.StatusUnauthorized)
} Prevention
- Match NewAccessValidator's domain/issuer/AUD to the exact Access team issuing tokens
- Decode and log the iss claim when diagnosing auth failures
- Ensure only the Cloudflare Access proxy can reach the origin (no direct ingress)
When it happens
Trigger: ValidateRequest receiving a Cf-Access-Jwt-Assertion JWT whose 'iss' claim is not a *.cloudflareaccess.com URL — e.g. token minted by a different Access team domain, another OIDC provider's token forwarded by a proxy, or a stale issuer configured in NewAccessValidator.
Common situations: Multiple Access applications/teams where the wrong team's token reaches this app; self-hosted or third-party OIDC tokens in the header; after migrating teams the validator still points at the old issuer; load balancers forwarding foreign JWTs.
Related errors
- token is nil: %s
- auth_domain %q does not end with %q
- metadata JWT auth_domain validation failed: %w
- metadata JWT verification failed: %w
- metadata JWT hostname %q does not match request host %q
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/544446ac25cc29fd.
Report an issue: GitHub.