{"record":{"id":"3ebbc263f27db369","repo":"quarkusio/quarkus","slug":"access-token-expires-in-property-in-the-session-co","errorCode":null,"errorMessage":"Access token expires_in property in the session cookie must be a number, found %s","messagePattern":"Access token expires_in property in the session cookie must be a number, found (.+?)","errorType":"exception","errorClass":"AuthenticationFailedException","httpStatus":401,"severity":"error","filePath":"extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/DefaultTokenStateManager.java","lineNumber":209,"sourceCode":"                    OidcUtils.removeCookie(routingContext, oidcConfig, cookieName);\n                }\n            }\n\n            OidcUtils.removeCookie(routingContext, getRefreshTokenCookie(routingContext, oidcConfig),\n                    oidcConfig);\n        }\n        return CodeAuthenticationMechanism.VOID_UNI;\n    }\n\n    private static Long parseAccessTokenExpiresIn(String accessTokenExpiresInString) {\n        try {\n            return Long.valueOf(accessTokenExpiresInString);\n        } catch (NumberFormatException ex) {\n            final String error = \"Access token expires_in property in the session cookie must be a number, found %s\"\n                    .formatted(accessTokenExpiresInString);\n            LOG.error(error);\n            // Make this error message visible in the dev mode\n            throw new AuthenticationFailedException(error);\n        }\n    }\n\n    private static String getAccessTokenCookie(RoutingContext routingContext, OidcTenantConfig oidcConfig) {\n        final Map<String, Cookie> cookies = OidcUtils.cookieSetToMap(routingContext.request().cookies());\n        return OidcUtils.getSessionCookie(routingContext.data(), cookies, oidcConfig, OidcUtils.SESSION_AT_COOKIE_NAME,\n                getAccessTokenCookieName(oidcConfig));\n    }\n\n    private static ServerCookie getRefreshTokenCookie(RoutingContext routingContext, OidcTenantConfig oidcConfig) {\n        return (ServerCookie) routingContext.request().getCookie(getRefreshTokenCookieName(oidcConfig));\n    }\n\n    private static String getAccessTokenCookieName(OidcTenantConfig oidcConfig) {\n        String cookieSuffix = OidcUtils.getCookieSuffix(oidcConfig);\n        return OidcUtils.SESSION_AT_COOKIE_NAME + cookieSuffix;\n    }\n","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/DefaultTokenStateManager.java#L191-L227","documentation":"DefaultTokenStateManager stores the access token's expiry (expires_in) in the encrypted/encoded q_session_at cookie. When reading tokens back (getTokens), parseAccessTokenExpiresIn() expects a numeric string; a non-numeric value raises AuthenticationFailedException so the failure is visible in dev mode.","triggerScenarios":"A request presents a session access-token cookie (q_session_at) whose second '|' segment is not parseable by Long.valueOf - e.g. a corrupted, hand-edited, truncated, or wrongly-encoded cookie value (when encryption is disabled the fields are base64url/plain pipe-separated and easy to tamper with).","commonSituations":"Cookie truncated by proxies or size limits; stale cookies written by a different Quarkus/OIDC version with a different cookie format; manual cookie manipulation or test tooling sending malformed values; encryption key change corrupting decryption producing garbage segments.","solutions":["Delete the malformed cookies (q_session / q_session_at / q_auth) in the browser or send the user through a fresh login so new cookies are written.","Verify cookie encryption secret/key configuration is stable across replicas and versions so decryption yields the intended format.","Upgrade/align Quarkus versions if cookies were produced by an incompatible OIDC format, or temporarily disable split-tokens strategy to simplify cookie content."],"exampleFix":"// before (client sends corrupted cookie)\nCookie: q_session_at=abc|not-a-number|scope\n\n// after - clear cookies and re-authenticate; ensure identical\n// quarkus.oidc.token-state-manager.encryption-secret across all replicas\nquarkus.oidc.token-state-manager.encryption-secret=same-value-everywhere","handlingStrategy":"try-catch","validationCode":"// Client-side sanity check before reusing an old session cookie\nString[] parts = atCookieValue.split(\"\\\\|\");\nboolean wellFormed = parts.length >= 2 && (parts[1].isEmpty() || parts[1].matches(\"\\\\d+\"));\nif (!wellFormed) { clearCookie(\"q_session_at\"); /* force re-login */ }","typeGuard":null,"tryCatchPattern":"try {\n    chain.doFilter(request, response);\n} catch (AuthenticationFailedException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"expires_in\")) {\n        // drop cookies and redirect to re-authenticate\n    }\n    throw e;\n}","preventionTips":["Keep quarkus.oidc.token-state-manager.encryption-secret identical across all replicas and stable across deploys","Avoid manual edits to session cookies in test tooling","After Quarkus major upgrades, invalidate old cookies (bump cookie-name suffix or force logout)","Monitor proxies for cookie truncation (4KB header limits)"],"tags":["oidc","cookie","session","corrupted-state"],"backgroundTag":"malformed-session-cookie","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}