From ff79afc57c66ca9d1688c577018f80f93c4b3595 Mon Sep 17 00:00:00 2001 From: Matthias Keck Date: Wed, 4 Sep 2024 15:04:54 +0200 Subject: [PATCH 1/2] Returns the oauth access token "expires at" date - in case the server did return it Fixes: SE-13502 --- .../web/security/oauth/ReceivedTokens.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/java/sirius/web/security/oauth/ReceivedTokens.java b/src/main/java/sirius/web/security/oauth/ReceivedTokens.java index 94d81c785..08a8ab8f2 100644 --- a/src/main/java/sirius/web/security/oauth/ReceivedTokens.java +++ b/src/main/java/sirius/web/security/oauth/ReceivedTokens.java @@ -22,10 +22,12 @@ * @param accessToken the access token received from the authorization server * @param refreshToken the refresh token received from the authorization server * @param type the type of the tokens received from the authorization server, e.g. "Bearer" or "MAC" + * @param accessTokenExpiresAt the date at which the access token expires, might be null if the server response + * contains no information * @param refreshTokenExpiresAt the date at which the refresh token expires, might be estimated if no JWT bearer * token is given */ -public record ReceivedTokens(String accessToken, String refreshToken, String type, +public record ReceivedTokens(String accessToken, String refreshToken, String type, LocalDateTime accessTokenExpiresAt, LocalDateTime refreshTokenExpiresAt) { private static final long TWO_DAYS_IN_SECONDS = 2 * 24 * 60 * 60L; @@ -41,26 +43,27 @@ public static ReceivedTokens fromJson(ObjectNode response) { String accessToken = response.required(OAuth.ACCESS_TOKEN).asText(""); String refreshToken = response.required(OAuth.REFRESH_TOKEN).asText(""); String type = response.required(OAuth.TOKEN_TYPE).asText(""); + long accessTokenExpiresIn = response.path(OAuth.EXPIRES_IN).asLong(0L); + LocalDateTime accessTokenExpiresAt = LocalDateTime.now().plusSeconds(accessTokenExpiresIn); if (OAuth.TOKEN_TYPE_BEARER.equalsIgnoreCase(type)) { try { // Try to read the exact refresh token expiration date from the JWT token itself LocalDateTime refreshTokenExpiresAt = JWT.decode(refreshToken).getExpiresAtAsInstant().atZone(ZoneOffset.UTC).toLocalDateTime(); - return new ReceivedTokens(accessToken, refreshToken, type, refreshTokenExpiresAt); + return new ReceivedTokens(accessToken, refreshToken, type, accessTokenExpiresAt, refreshTokenExpiresAt); } catch (JWTDecodeException exception) { // No valid JWT, fall back to implementation from OAuth expires_in or the default value } } - // Check if the 'expires in' field, actually meant for the access token, is better than our default tomorrow. - long expiresIn = response.path(OAuth.EXPIRES_IN).asLong(0L); - if (expiresIn > TWO_DAYS_IN_SECONDS) { - LocalDateTime expiresDate = LocalDateTime.now().plusSeconds(expiresIn); - return new ReceivedTokens(accessToken, refreshToken, type, expiresDate); + // Check if the 'expires in' field, actually meant for the access token, is better than our refresh token + // default expires value tomorrow. + if (accessTokenExpiresIn > TWO_DAYS_IN_SECONDS) { + return new ReceivedTokens(accessToken, refreshToken, type, accessTokenExpiresAt, accessTokenExpiresAt); } // Use default value tomorrow, we expect a refresh token to be valid at least for one more day LocalDateTime expiresDate = LocalDateTime.now().plusDays(MINIMUM_REFRESH_EXPIRES_DAYS); - return new ReceivedTokens(accessToken, refreshToken, type, expiresDate); + return new ReceivedTokens(accessToken, refreshToken, type, accessTokenExpiresAt, expiresDate); } } From 3f6ad004ad40cba03ae9ec0d8ef63006061eeae2 Mon Sep 17 00:00:00 2001 From: Matthias Keck Date: Wed, 4 Sep 2024 15:33:12 +0200 Subject: [PATCH 2/2] Fixes accessTokenExpiresAt default value - as per RFC the containing field is optional - the accessTokenExpiresAt is not strictly required by our implementations as well - so make it null in case it cannot be determined from server response Fixes: SE-13502 --- src/main/java/sirius/web/security/oauth/ReceivedTokens.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/sirius/web/security/oauth/ReceivedTokens.java b/src/main/java/sirius/web/security/oauth/ReceivedTokens.java index 08a8ab8f2..85a127287 100644 --- a/src/main/java/sirius/web/security/oauth/ReceivedTokens.java +++ b/src/main/java/sirius/web/security/oauth/ReceivedTokens.java @@ -44,7 +44,8 @@ public static ReceivedTokens fromJson(ObjectNode response) { String refreshToken = response.required(OAuth.REFRESH_TOKEN).asText(""); String type = response.required(OAuth.TOKEN_TYPE).asText(""); long accessTokenExpiresIn = response.path(OAuth.EXPIRES_IN).asLong(0L); - LocalDateTime accessTokenExpiresAt = LocalDateTime.now().plusSeconds(accessTokenExpiresIn); + LocalDateTime accessTokenExpiresAt = + accessTokenExpiresIn > 0 ? LocalDateTime.now().plusSeconds(accessTokenExpiresIn) : null; if (OAuth.TOKEN_TYPE_BEARER.equalsIgnoreCase(type)) { try { // Try to read the exact refresh token expiration date from the JWT token itself