{"record":{"id":"b25f442b11b03f02","repo":"neondatabase/neon","slug":"configured-for-jwt-auth-with-zero-decoding-keys-a","errorCode":null,"errorMessage":"Configured for JWT auth with zero decoding keys. All JWT gated requests would be rejected.","messagePattern":"Configured for JWT auth with zero decoding keys\\. All JWT gated requests would be rejected\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/utils/src/auth.rs","lineNumber":171,"sourceCode":"            let mut keys = Vec::new();\n            for entry in fs::read_dir(key_path)? {\n                let path = entry?.path();\n                if !path.is_file() {\n                    // Ignore directories (don't recurse)\n                    continue;\n                }\n                let public_key = fs::read(path)?;\n                keys.push(DecodingKey::from_ed_pem(&public_key)?);\n            }\n            keys\n        } else if metadata.is_file() {\n            let public_key = fs::read(key_path)?;\n            vec![DecodingKey::from_ed_pem(&public_key)?]\n        } else {\n            anyhow::bail!(\"path is neither a directory or a file\")\n        };\n        if decoding_keys.is_empty() {\n            anyhow::bail!(\n                \"Configured for JWT auth with zero decoding keys. All JWT gated requests would be rejected.\"\n            );\n        }\n        Ok(Self::new(decoding_keys))\n    }\n\n    pub fn from_key(key: String) -> Result<Self> {\n        Ok(Self::new(vec![DecodingKey::from_ed_pem(key.as_bytes())?]))\n    }\n\n    /// Attempt to decode the token with the internal decoding keys.\n    ///\n    /// The function tries the stored decoding keys in succession,\n    /// and returns the first yielding a successful result.\n    /// If there is no working decoding key, it returns the last error.\n    pub fn decode<D: DeserializeOwned>(\n        &self,\n        token: &str,","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/libs/utils/src/auth.rs#L153-L189","documentation":"from_key_path accepts a directory to support key rotation, but if that directory contains no loadable regular files the constructor bails. With zero decoding keys every JWT-gated request would be rejected, so the library fails fast at startup instead of running in an always-deny state.","triggerScenarios":"The configured JWT key directory exists but is empty: a Kubernetes secret volume that was never populated, a failed/renamed secret mount, or an automation step that skipped key provisioning.","commonSituations":"k8s secret mounted empty due to name mismatch or missing items; key rotation removed old files before new ones landed; fresh environments missing the provisioning step.","solutions":["Ensure at least one Ed25519 public key PEM exists in the directory","Check the deployment/mount: kubectl describe pod, verify secret name and mountPath","Add a provisioning step that writes keys before the service starts"],"exampleFix":"# before: secret mounted but empty\nvolumes:\n  - name: jwt-keys\n    secret:\n      secretName: jwt-keys-wrong-name\n# after\nkubectl create secret generic jwt-keys --from-file=public.pem=./public.pem\n# files land at /etc/neon/keys/public.pem","handlingStrategy":"validation","validationCode":"fn key_dir_has_pem(dir: &camino::Utf8Path) -> bool {\n    std::fs::read_dir(dir)\n        .map(|entries| entries.filter_map(Result::ok).any(|e| e.path().is_file()))\n        .unwrap_or(false)\n}\n\n// run before JwtAuth::from_key_path\nanyhow::ensure!(key_dir_has_pem(&key_path), \"JWT key directory is empty\");","typeGuard":"fn is_zero_keys_error(err: &anyhow::Error) -> bool {\n    err.to_string().contains(\"zero decoding keys\")\n}","tryCatchPattern":"match JwtAuth::from_key_path(&key_path) {\n    Err(e) if e.to_string().contains(\"zero decoding keys\") => {\n        eprintln!(\"key directory {key_path} contains no PEM files; provision keys first\");\n        std::process::exit(1);\n    }\n    other => other?,\n}","preventionTips":["Verify secret mounts are non-empty before service start (initContainer or entrypoint check)","Make key provisioning an explicit deployment step","Alert on empty key directories during rotation windows"],"tags":["auth","jwt","rust","config","kubernetes"],"backgroundTag":"missing-jwt-public-key","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}