Skip to content

Commit b5e3eb9

Browse files
committed
Fix null expected value throwing NullPointerException in JWTVerifier
Registering a null expected value (e.g. withSubject(null), withJWTId(null), withClaim(name, (Integer) null)) documents the intent "this claim must be JSON null". When the token actually carried the claim, verifyNull() returned false and the code then called value.equals(claim.asX()) on the null expected value, leaking a raw NullPointerException out of verify() instead of the documented IncorrectClaimException. Use the null-safe Objects.equals(value, claim.asX()) at every value-claim site (withSubject, withJWTId, the typed withClaim overloads, and the Instant overload, which withClaim(Date) delegates to). Behaviour is identical when the value is non-null; when it is null and the claim is present, verification now fails with IncorrectClaimException. No public API change.
1 parent f720a21 commit b5e3eb9

2 files changed

Lines changed: 19 additions & 8 deletions

File tree

lib/src/main/java/com/auth0/jwt/JWTVerifier.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public Verification withIssuer(String... issuer) {
9090
@Override
9191
public Verification withSubject(String subject) {
9292
addCheck(RegisteredClaims.SUBJECT, (claim, decodedJWT) ->
93-
verifyNull(claim, subject) || subject.equals(claim.asString()));
93+
verifyNull(claim, subject) || Objects.equals(subject, claim.asString()));
9494
return this;
9595
}
9696

@@ -163,7 +163,7 @@ public Verification ignoreIssuedAt() {
163163
@Override
164164
public Verification withJWTId(String jwtId) {
165165
addCheck(RegisteredClaims.JWT_ID, ((claim, decodedJWT) ->
166-
verifyNull(claim, jwtId) || jwtId.equals(claim.asString())));
166+
verifyNull(claim, jwtId) || Objects.equals(jwtId, claim.asString())));
167167
return this;
168168
}
169169

@@ -186,39 +186,39 @@ public Verification withNullClaim(String name) throws IllegalArgumentException {
186186
public Verification withClaim(String name, Boolean value) throws IllegalArgumentException {
187187
assertNonNull(name);
188188
addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, value)
189-
|| value.equals(claim.asBoolean())));
189+
|| Objects.equals(value, claim.asBoolean())));
190190
return this;
191191
}
192192

193193
@Override
194194
public Verification withClaim(String name, Integer value) throws IllegalArgumentException {
195195
assertNonNull(name);
196196
addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, value)
197-
|| value.equals(claim.asInt())));
197+
|| Objects.equals(value, claim.asInt())));
198198
return this;
199199
}
200200

201201
@Override
202202
public Verification withClaim(String name, Long value) throws IllegalArgumentException {
203203
assertNonNull(name);
204204
addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, value)
205-
|| value.equals(claim.asLong())));
205+
|| Objects.equals(value, claim.asLong())));
206206
return this;
207207
}
208208

209209
@Override
210210
public Verification withClaim(String name, Double value) throws IllegalArgumentException {
211211
assertNonNull(name);
212212
addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, value)
213-
|| value.equals(claim.asDouble())));
213+
|| Objects.equals(value, claim.asDouble())));
214214
return this;
215215
}
216216

217217
@Override
218218
public Verification withClaim(String name, String value) throws IllegalArgumentException {
219219
assertNonNull(name);
220220
addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, value)
221-
|| value.equals(claim.asString())));
221+
|| Objects.equals(value, claim.asString())));
222222
return this;
223223
}
224224

@@ -234,7 +234,7 @@ public Verification withClaim(String name, Instant value) throws IllegalArgument
234234
// we need to compare them with only seconds-granularity
235235
addCheck(name,
236236
((claim, decodedJWT) -> verifyNull(claim, value)
237-
|| value.truncatedTo(ChronoUnit.SECONDS).equals(claim.asInstant())));
237+
|| (value != null && value.truncatedTo(ChronoUnit.SECONDS).equals(claim.asInstant()))));
238238
return this;
239239
}
240240

lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,4 +1314,15 @@ public void shouldCheckForWrongIntegerArrayClaim() {
13141314
});
13151315
assertThat(e.getClaimName(), is("custom"));
13161316
}
1317+
1318+
@Test
1319+
public void shouldThrowIncorrectClaimNotNpeWhenNullSubjectExpectedButClaimPresent() {
1320+
// H4: registering a null expected value means "the claim must be JSON null"; when the token
1321+
// actually carries the claim, verification must fail with the documented IncorrectClaimException,
1322+
// not leak a raw NullPointerException out of verify().
1323+
String token = JWT.create().withSubject("actual").sign(Algorithm.HMAC256("secret"));
1324+
IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () ->
1325+
JWTVerifier.init(Algorithm.HMAC256("secret")).withSubject(null).build().verify(token));
1326+
assertThat(e.getClaimName(), is("sub"));
1327+
}
13171328
}

0 commit comments

Comments
 (0)