{"record":{"id":"aa3e76ac73b9b938","repo":"apache/dolphinscheduler","slug":"oidc-id-token-expired","errorCode":"OIDC_ID_TOKEN_EXPIRED","errorMessage":"OIDC_ID_TOKEN_EXPIRED","messagePattern":"OIDC_ID_TOKEN_EXPIRED","errorType":"error_code","errorClass":"ServiceException","httpStatus":null,"severity":"error","filePath":"dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/oidc/OidcAuthenticator.java","lineNumber":293,"sourceCode":"        try {\n            claimsSet = idToken.getJWTClaimsSet();\n        } catch (java.text.ParseException e) {\n            throw new ServiceException(\"Error parsing ID token claims\", e);\n        }\n\n        String issuer = claimsSet.getIssuer();\n        if (issuer == null || !issuer.equals(providerMetadata.getIssuer().getValue())) {\n            throw new ServiceException(Status.OIDC_ID_TOKEN_ISSUER_INVALID);\n        }\n\n        List<String> audiences = claimsSet.getAudience();\n        if (audiences == null || !audiences.contains(providerConfig.getClientId())) {\n            throw new ServiceException(Status.OIDC_ID_TOKEN_AUDIENCE_INVALID);\n        }\n\n        Date expirationTime = claimsSet.getExpirationTime();\n        if (expirationTime == null || expirationTime.before(new Date())) {\n            throw new ServiceException(Status.OIDC_ID_TOKEN_EXPIRED);\n        }\n\n        try {\n            return new IDTokenClaimsSet(claimsSet);\n        } catch (ParseException e) {\n            log.error(\"Failed to parse ID token claims, required claims may be missing.\", e);\n            throw new ServiceException(\"ID token is missing required claims\", e);\n        }\n    }\n\n    /**\n     * Get user info from UserInfo endpoint\n     */\n    private UserInfo getUserInfo(OIDCProviderMetadata providerMetadata, AccessToken accessToken) throws Exception {\n        UserInfoRequest userInfoRequest = new UserInfoRequest(\n                providerMetadata.getUserInfoEndpointURI(),\n                accessToken);\n","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/apache/dolphinscheduler/blob/02eac45a1b6676e639fcbfb4be2243de5771b05d/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/oidc/OidcAuthenticator.java#L275-L311","documentation":"validateIdToken reads the exp claim and throws ServiceException(Status.OIDC_ID_TOKEN_EXPIRED) when the expiration time is null or already in the past. ID tokens are short-lived (typically minutes); this error means the token can no longer be trusted for login because its validity window has ended.","triggerScenarios":"idTokenClaims -> validateIdToken with an ID token whose exp claim is missing or whose exp < now — e.g. finishing the OAuth callback after the token expired, clock skew between server and IdP, or replaying a captured token long after issuance.","commonSituations":"User sat on the login redirect page longer than the token lifetime; large clock drift between the DolphinScheduler host and the identity provider; authorization-code exchange retried with a cached/stale id_token; debugging with an old token copied from logs.","solutions":["Restart the login flow to obtain a fresh ID token instead of reusing the old one.","Sync the server clock (NTP) on the DolphinScheduler host; clock skew makes freshly issued tokens appear expired.","Check the IdP's token lifetime settings and increase them only if login flows legitimately take longer than the lifetime.","Make sure the authorization-code exchange happens immediately in the callback and is not retried with cached responses."],"exampleFix":"// before: reusing a stored id_token from a previous session\nJWT idToken = cachedIdToken; // exp already passed\n\n// after: always exchange the fresh authorization code\nOIDCTokenResponse resp = tokenRequest(authorizationCode);\nJWT idToken = resp.getOIDCTokens().getIDToken();","handlingStrategy":"try-catch","validationCode":"// check expiry client-side before calling validation\nDate exp = decoded.getExpirationTime();\nif (exp == null || exp.before(new Date())) {\n    throw new IllegalStateException(\"ID token already expired, restart login\");\n}","typeGuard":"boolean isUsable(JWTClaimsSet c) {\n    try { Date e = c.getExpirationTime(); return e != null && e.after(new Date()); }\n    catch (java.text.ParseException ex) { return false; }\n}","tryCatchPattern":"try {\n    return idTokenClaims(providerMetadata, providerConfig, idToken);\n} catch (ServiceException e) {\n    // expired token: restart the auth flow for a fresh one\n    return initiateNewAuthorizationRequest();\n}","preventionTips":["Exchange the authorization code immediately in the callback; never cache id_tokens.","Run NTP on DolphinScheduler hosts to keep clock skew near zero.","Keep IdP token lifetimes reasonable relative to your login flow duration.","Detect expiry proactively and redirect to re-authentication instead of erroring."],"tags":["oidc","jwt","token-expired","clock-skew"],"backgroundTag":"jwt-token-expired","analyzedSha":"02eac45a1b6676e639fcbfb4be2243de5771b05d","analyzedAt":"2026-09-06T17:43:00.555Z","contentChangedAt":"2026-09-06T17:43:00.555Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}