{"record":{"id":"d8eaa704bcaead55","repo":"cloudflare/cloudflared","slug":"failed-to-parse-jwt","errorCode":null,"errorMessage":"failed to parse JWT","messagePattern":"failed to parse JWT","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sshgen/sshgen.go","lineNumber":95,"sourceCode":"// handleCertificateGeneration takes a JWT and uses it build a signPayload\n// to send to the Sign endpoint with the public key from the keypair it generated\nfunc handleCertificateGeneration(token, fullName string) (string, error) {\n\tpub, err := generateKeyPair(fullName)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn SignCert(token, string(pub))\n}\n\nfunc SignCert(token, pubKey string) (string, error) {\n\tif token == \"\" {\n\t\treturn \"\", errors.New(\"invalid token\")\n\t}\n\n\tparsedToken, err := jwt.ParseSigned(token, signatureAlgs)\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"failed to parse JWT\")\n\t}\n\n\tclaims := jwt.Claims{}\n\terr = parsedToken.UnsafeClaimsWithoutVerification(&claims)\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"failed to retrieve JWT claims\")\n\t}\n\n\tbuf, err := json.Marshal(&signPayload{\n\t\tPublicKey: pubKey,\n\t\tJWT:       token,\n\t\tIssuer:    claims.Issuer,\n\t})\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"failed to marshal signPayload\")\n\t}\n\tvar res *http.Response\n\tif mockRequest != nil {","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/sshgen/sshgen.go#L77-L113","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n$ export ACCESS_TOKEN=eyJhbGciOi (truncated paste)\n$ cloudflared access ssh-gen --token $ACCESS_TOKEN\n// after\n$ export ACCESS_TOKEN=$(cat ~/cf_access_token)  # full JWT, no newlines\n$ cloudflared access ssh-gen --token \"$ACCESS_TOKEN\"","handlingStrategy":"validation","validationCode":"// validate token shape before invoking SignCert\nfunc validJWSShape(token string) bool {\n    token = strings.TrimSpace(token)\n    if token == \"\" {\n        return false\n    }\n    parts := strings.Split(token, \".\")\n    return len(parts) == 3 && parts[0] != \"\" && parts[1] != \"\" && parts[2] != \"\"\n}\nif !validJWSShape(token) {\n    return errors.New(\"token is not a well-formed JWT (expected header.payload.signature)\")\n}","typeGuard":"func isLikelyJWT(s string) bool {\n    s = strings.TrimSpace(s)\n    parts := strings.Split(s, \".\")\n    return len(parts) == 3\n}","tryCatchPattern":"token, err := signCert(ctx, token)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to parse JWT\") {\n        return fmt.Errorf(\"the provided Cloudflare Access token is malformed; re-copy the full CF_Authorization value: %w\", err)\n    }\n    return err\n}","preventionTips":["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."],"tags":["jwt","authentication","ssh","cloudflare-access","parsing"],"backgroundTag":"jwt-token-expired","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}