cloudflare/cloudflared · error

failed to retrieve JWT claims

Error message

failed to retrieve JWT claims

What it means

SignCert parses a JWT token and extracts its claims to build a certificate signing request. This error means the token itself parsed, but the claim payload inside could not be decoded into jwt.Claims via UnsafeClaimsWithoutVerification. The library wraps the underlying decode failure so the caller knows which phase of token processing failed.

Source

Thrown at sshgen/sshgen.go:101

	}

	return SignCert(token, string(pub))
}

func SignCert(token, pubKey string) (string, error) {
	if token == "" {
		return "", errors.New("invalid token")
	}

	parsedToken, err := jwt.ParseSigned(token, signatureAlgs)
	if err != nil {
		return "", errors.Wrap(err, "failed to parse JWT")
	}

	claims := jwt.Claims{}
	err = parsedToken.UnsafeClaimsWithoutVerification(&claims)
	if err != nil {
		return "", errors.Wrap(err, "failed to retrieve JWT claims")
	}

	buf, err := json.Marshal(&signPayload{
		PublicKey: pubKey,
		JWT:       token,
		Issuer:    claims.Issuer,
	})
	if err != nil {
		return "", errors.Wrap(err, "failed to marshal signPayload")
	}
	var res *http.Response
	if mockRequest != nil {
		res, err = mockRequest(claims.Issuer+signEndpoint, "application/json", bytes.NewBuffer(buf))
	} else {
		client := http.Client{
			Timeout: 10 * time.Second,
		}
		res, err = client.Post(claims.Issuer+signEndpoint, "application/json", bytes.NewBuffer(buf))

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Verify the token is a real JWT with three dot-separated base64 segments and a JSON payload
  2. Decode the payload (e.g. base64 -d on the middle segment) and confirm the claims parse as JSON with the expected fields
  3. Re-run `cloudflared login` to obtain a fresh, well-formed token from Cloudflare
  4. Check for accidental whitespace/newlines or truncation when the token was copied into configuration

Example fix

// before
err = parsedToken.UnsafeClaimsWithoutVerification(&claims)
// after
if parsedToken == nil {
    return "", errors.New("nil token")
}
if err = parsedToken.UnsafeClaimsWithoutVerification(&claims); err != nil {
    return "", errors.Wrap(err, "failed to retrieve JWT claims")
}
Defensive patterns

Strategy: validation

Validate before calling

// validate token shape before calling SignCert
parts := strings.Split(token, ".")
if len(parts) != 3 {
    return errors.New("token is not a JWT (expected 3 segments)")
}
payload, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil {
    return fmt.Errorf("JWT payload not base64url: %w", err)
}
var probe map[string]json.RawMessage
if err := json.Unmarshal(payload, &probe); err != nil {
    return fmt.Errorf("JWT payload not valid JSON: %w", err)
}

Try / catch

if _, err := SignCert(token, pubKey); err != nil {
    if strings.Contains(err.Error(), "failed to retrieve JWT claims") {
        // regenerate token via `cloudflared access login` and retry once
    }
}

Prevention

When it happens

Trigger: SignCert is called with a JWT whose decoded payload is not valid JSON or does not map to the expected claim fields (e.g. issuer not a string).

Common situations: Passing a corrupted or hand-edited token from cloudflared's config; passing a non-JWT opaque token; using a token whose claims contain unexpected types after an upstream format change.

Related errors


AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/2870d2913d0bd38f. Report an issue: GitHub.