{"record":{"id":"5e91f986d2258f36","repo":"influxdata/influxdb","slug":"jwt-has-expired","errorCode":null,"errorMessage":"JWT has expired","messagePattern":"JWT has expired","errorType":"error_code","errorClass":"AuthenticatorError","httpStatus":null,"severity":"error","filePath":"influxdb3_authz/src/lib.rs","lineNumber":91,"sourceCode":"    ResourceNotSupported(String),\n}\n\n#[derive(Debug, thiserror::Error)]\npub enum AuthenticatorError {\n    /// Error for token that is present in the request but missing in the catalog\n    #[error(\"token provided is not present in catalog\")]\n    InvalidToken,\n    /// Error for token that has expired\n    #[error(\"token has expired {0}\")]\n    ExpiredToken(String),\n    /// Error for missing token (this should really be handled at the HTTP/Grpc API layer itself)\n    #[error(\"missing token to authenticate\")]\n    MissingToken,\n    /// Error for invalid JWT (bad signature, malformed, etc.)\n    #[error(\"invalid JWT\")]\n    InvalidJwt,\n    /// Error for expired JWT\n    #[error(\"JWT has expired\")]\n    ExpiredJwt,\n}\n\nimpl From<AuthenticatorError> for IoxError {\n    fn from(err: AuthenticatorError) -> Self {\n        match err {\n            AuthenticatorError::InvalidToken => IoxError::NoToken,\n            AuthenticatorError::ExpiredToken(token_expiry_time) => {\n                // there is no mapping to let the caller know about expired token in iox so\n                // we just log it for now (only useful in debugging)\n                debug!(?token_expiry_time, \"supplied token has expired\");\n                IoxError::InvalidToken\n            }\n            AuthenticatorError::MissingToken => IoxError::NoToken,\n            AuthenticatorError::InvalidJwt => IoxError::InvalidToken,\n            AuthenticatorError::ExpiredJwt => {\n                debug!(\"JWT has expired\");\n                IoxError::InvalidToken","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/influxdata/influxdb/blob/06200ef96ba82c5f6727e5038a83af8e722c6875/influxdb3_authz/src/lib.rs#L73-L109","documentation":"AuthenticatorError::ExpiredJwt is returned when a JWT is structurally valid and correctly signed but its `exp` claim is in the past. The authenticator distinguishes this from expired catalog tokens (ExpiredToken) and invalid JWTs (InvalidJwt). The request must be retried with a freshly issued JWT.","triggerScenarios":"Using a cached JWT beyond its expiry; long-lived connections that keep sending an initially validated JWT; identity-provider sessions ending while the client keeps the old token.","commonSituations":"Clients without token refresh logic; SDKs holding a JWT for hours; services that fetch a JWT at boot and never refresh it.","solutions":["Request a new JWT from the identity provider and retry","Implement automatic refresh before the `exp` claim elapses","Increase JWT lifetime if appropriate for the workload"],"exampleFix":"// before: jwt fetched once at startup\nlet jwt = fetch_jwt();\nloop { send_request(&jwt); }\n// after: refresh on expiry\nloop {\n    if jwt.expiring_within(60) { jwt = fetch_jwt(); }\n    send_request(&jwt);\n}","handlingStrategy":"retry","validationCode":"// check exp claim before sending\nlet exp: i64 = jwt_claims[\"exp\"];\nif exp <= Utc::now().timestamp() { jwt = refresh_jwt()?; }","typeGuard":null,"tryCatchPattern":"match request() {\n    Err(AuthenticatorError::ExpiredJwt) => {\n        jwt = refresh_jwt()?;  // re-issue from IdP\n        request()              // single retry\n    }\n    r => r,\n}","preventionTips":["Implement JWT refresh scheduled ahead of the exp claim","Don't cache JWTs beyond their lifetime in processes or CI caches","Monitor refresh failures with alerts before expiry causes outages"],"tags":["authentication","jwt","expired","influxdb3"],"backgroundTag":"jwt-token-expired","analyzedSha":"06200ef96ba82c5f6727e5038a83af8e722c6875","analyzedAt":"2026-09-19T12:55:30.003Z","contentChangedAt":"2026-09-19T12:55:30.003Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}