Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions core/src/main/java/tech/ydb/core/auth/JwtUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,14 @@ public static Instant extractExpireAt(String jwt, Instant defaultValue) {
}

try {
String payload = new String(Base64.getDecoder().decode(parts[1]), StandardCharsets.UTF_8);
String payload = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8);
JwtClaims claims = GSON.fromJson(payload, JwtClaims.class);
if (claims != null && claims.getExpiredAt() != null) {
return Instant.ofEpochSecond(claims.getExpiredAt());
}
} catch (IllegalArgumentException | JsonSyntaxException ex) {
logger.error("can't get expire from jwt {}", jwt, ex);
// the JWT itself is a credential and must never be logged
logger.error("Can't get expire from JWT", ex);
}

return defaultValue;
Expand Down
3 changes: 2 additions & 1 deletion core/src/test/java/tech/ydb/core/auth/JwtBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ public static String create(Instant expiredAt, Instant issuedAt) {
sb.append("\"iss\":\"").append("MOCK").append("\"");
sb.append("}");

String base64 = Base64.getEncoder().encodeToString(sb.toString().getBytes(StandardCharsets.UTF_8));
String base64 = Base64.getUrlEncoder().withoutPadding()
.encodeToString(sb.toString().getBytes(StandardCharsets.UTF_8));

return PREFIX + base64;
}
Expand Down
17 changes: 17 additions & 0 deletions core/src/test/java/tech/ydb/core/auth/JwtUtilsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,21 @@ public void parseTest() {
Assert.assertEquals(Instant.ofEpochSecond(1726544488), JwtUtils.extractExpireAt(jwt2, Instant.EPOCH));
Assert.assertEquals(Instant.ofEpochSecond(1726544488), JwtUtils.extractExpireAt(jwt3, Instant.EPOCH));
}

@Test
public void parseBase64UrlPayloadTest() {
// JWT payloads use the base64url alphabet, so they may contain '-' and '_' instead of '+' and '/'
// { "alg": "HS256", "typ": "JWT" }.{ "sub": "a?b>c", "aud": "x?y?z", "exp": 1726544488 }
String jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
+ ".eyJzdWIiOiJhP2I-YyIsImF1ZCI6Ing_eT96IiwiZXhwIjoxNzI2NTQ0NDg4fQ";

Assert.assertEquals(Instant.ofEpochSecond(1726544488), JwtUtils.extractExpireAt(jwt, Instant.EPOCH));
}

@Test
public void unparsablePayloadReturnsDefaultTest() {
String jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.!not-a-base64-payload!";

Assert.assertEquals(Instant.EPOCH, JwtUtils.extractExpireAt(jwt, Instant.EPOCH));
}
}
Loading