{"record":{"id":"03bdc5eb4fbdacab","repo":"cloudflare/cloudflared","slug":"invalid-token","errorCode":null,"errorMessage":"invalid token","messagePattern":"invalid token","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sshgen/sshgen.go","lineNumber":90,"sourceCode":"\t}\n\n\treturn nil\n}\n\n// 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})","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/sshgen/sshgen.go#L72-L108","documentation":"SignCert in sshgen returns \"invalid token\" when the Cloudflare Access JWT passed to it is empty. Before parsing the JWT with jwt.ParseSigned, the function rejects an empty token because no certificate can be signed without credentials identifying the requester.","triggerScenarios":"Calling cloudflared's SSH certificate generation (handleCertificateGeneration -> SignCert) with a token string that is empty — e.g. the cf_access_token / Cloudflare Access JWT was never fetched, the `--token` flag was omitted, or an environment/config lookup returned \"\".","commonSituations":"Running `cloudflared access ssh-gen` or short-lived SSH cert flow without being logged in to Cloudflare Access; the Access token file/env var missing on the host; a token-fetch step failing silently upstream and passing an empty string onward.","solutions":["Obtain a valid Cloudflare Access JWT first (cloudflared access login / `cloudflared access token --app <url>`) and pass it to SignCert.","Check that the token source (flag, env var, or token file) is populated and the path/env name is correct before calling SignCert.","Add an explicit empty check in the caller so the failure is reported with context about where the token should come from.","If the token was expected to be refreshed automatically, verify the Access app/service-token configuration and clock/expiry handling."],"exampleFix":"// before\n_, err := sshgen.SignCert(\"\", pubKey)\n// after\ntoken := os.Getenv(\"CF_ACCESS_TOKEN\")\nif token == \"\" {\n    return errors.New(\"missing Cloudflare Access token; run `cloudflared access login` first\")\n}\ncert, err := sshgen.SignCert(token, pubKey)","handlingStrategy":"validation","validationCode":"if token == \"\" {\n    return errors.New(\"missing Cloudflare Access token; run `cloudflared access login`\")\n}\ncert, err := sshgen.SignCert(token, pubKey)","typeGuard":"func hasToken(token string) bool { return strings.TrimSpace(token) != \"\" }","tryCatchPattern":"cert, err := sshgen.SignCert(token, pubKey)\nif err != nil && strings.Contains(err.Error(), \"invalid token\") {\n    // prompt user to authenticate / fetch a fresh Access JWT\n}","preventionTips":["Fetch the Access JWT immediately before signing so it cannot be stale or empty.","Fail fast in callers when the token source (flag/env/file) yields an empty string.","Log which token source was used to make empty-token misconfigurations obvious."],"tags":["ssh","jwt","authentication","cloudflare-access"],"backgroundTag":"missing-api-key","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"}