cloudflare/cloudflared · error
failed to parse JWT
Error message
failed to parse JWT
What it means
sshgen.SignCert parses the Cloudflare Access short-lived JWT (cf-access token) supplied by the user using go-jose's jwt.ParseSigned with the allowed signature algorithms. If the token string is not a well-formed JWS (wrong format, truncated, tampered, or empty-looking), the parse fails and the error is wrapped as 'failed to parse JWT'. No signature verification has happened yet at this stage — this is purely a syntax/structure failure.
Source
Thrown at sshgen/sshgen.go:95
// handleCertificateGeneration takes a JWT and uses it build a signPayload
// to send to the Sign endpoint with the public key from the keypair it generated
func handleCertificateGeneration(token, fullName string) (string, error) {
pub, err := generateKeyPair(fullName)
if err != nil {
return "", err
}
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 {View on GitHub (pinned to 2253eeeb25)
Solutions
- Re-copy the full Cloudflare Access JWT (the CF_Authorization cookie value) — ensure nothing was truncated or had whitespace added.
- Verify the token has the three dot-separated JWS parts (header.payload.signature).
- Re-authenticate to Cloudflare Access in the browser to obtain a fresh token before running the command.
- Confirm you are passing the token to the right flag/env var for the sshgen command, not a different credential.
Example fix
// before $ export ACCESS_TOKEN=eyJhbGciOi (truncated paste) $ cloudflared access ssh-gen --token $ACCESS_TOKEN // after $ export ACCESS_TOKEN=$(cat ~/cf_access_token) # full JWT, no newlines $ cloudflared access ssh-gen --token "$ACCESS_TOKEN"
Defensive patterns
Strategy: validation
Validate before calling
// validate token shape before invoking SignCert
func validJWSShape(token string) bool {
token = strings.TrimSpace(token)
if token == "" {
return false
}
parts := strings.Split(token, ".")
return len(parts) == 3 && parts[0] != "" && parts[1] != "" && parts[2] != ""
}
if !validJWSShape(token) {
return errors.New("token is not a well-formed JWT (expected header.payload.signature)")
} Type guard
func isLikelyJWT(s string) bool {
s = strings.TrimSpace(s)
parts := strings.Split(s, ".")
return len(parts) == 3
} Try / catch
token, err := signCert(ctx, token)
if err != nil {
if strings.Contains(err.Error(), "failed to parse JWT") {
return fmt.Errorf("the provided Cloudflare Access token is malformed; re-copy the full CF_Authorization value: %w", err)
}
return err
} Prevention
- Always fetch a fresh Access token right before running ssh-gen — tokens are short-lived.
- Read the token from a file or env var instead of manual copy/paste to avoid truncation.
- Strip surrounding whitespace/newlines before passing the token.
- Sanity-check the three dot-separated segments before submitting the token.
When it happens
Trigger: jwt.ParseSigned(token, signatureAlgs) errors: the token passed to cloudflared ssh-gen / certificate generation is empty, truncated, base64-corrupt, or not a JWS compact serialization at all.
Common situations: User pasted only part of the Access token, copied the wrong header (e.g. a CSP nonce or session cookie instead of CF_Authorization), environment variable with the token unset or containing whitespace/newlines, or an old token format from a deprecated Access flow.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- invalid token
- failed to parse metadata JWT
- metadata JWT aud is empty
- metadata JWT iat is missing or invalid
- failed to parse auth_domain %q: %w
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/d8eaa704bcaead55.
Report an issue: GitHub.