Skip to content

Commit 7338cbe

Browse files
committed
refactor: wrap in 2 main exceptions decode and verify. add javadocs
1 parent 363e10e commit 7338cbe

29 files changed

Lines changed: 307 additions & 106 deletions

lib/src/main/java/com/auth0/jwtdecodejava/JWTDecoder.java

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.auth0.jwtdecodejava;
22

33
import com.auth0.jwtdecodejava.algorithms.Algorithm;
4-
import com.auth0.jwtdecodejava.exceptions.JWTException;
4+
import com.auth0.jwtdecodejava.exceptions.JWTDecodeException;
55
import com.auth0.jwtdecodejava.impl.JWTParser;
66
import com.auth0.jwtdecodejava.interfaces.Claim;
77
import com.auth0.jwtdecodejava.interfaces.Header;
@@ -10,27 +10,44 @@
1010

1111
import java.util.Date;
1212

13-
import static com.auth0.jwtdecodejava.SignUtils.base64Decode;
14-
13+
/**
14+
* The JWTDecoder class holds the decode method to parse a given Token into it's JWT representation.
15+
*/
1516
public final class JWTDecoder implements JWT {
1617

1718
private Header header;
1819
private Payload payload;
1920
private String signature;
2021

21-
private JWTDecoder(String jwt) {
22+
private JWTDecoder(String jwt) throws JWTDecodeException {
2223
parseToken(jwt);
2324
}
2425

25-
public static JWT decode(String jwt) {
26-
return new JWTDecoder(jwt);
26+
/**
27+
* Decode a given Token into a JWT instance.
28+
* Note that this method doesn't verify the JWT's signature! Use it only if you trust the issuer of the Token.
29+
*
30+
* @param token the String representation of the JWT.
31+
* @return a decoded JWT.
32+
* @throws JWTDecodeException if any part of the Token contained an invalid JWT or JSON format.
33+
*/
34+
public static JWT decode(String token) throws JWTDecodeException {
35+
return new JWTDecoder(token);
2736
}
2837

29-
private void parseToken(String token) throws JWTException {
38+
private void parseToken(String token) throws JWTDecodeException {
3039
final String[] parts = SignUtils.splitToken(token);
3140
final JWTParser converter = new JWTParser();
32-
header = converter.parseHeader(base64Decode(parts[0]));
33-
payload = converter.parsePayload(base64Decode(parts[1]));
41+
String headerJson;
42+
String payloadJson;
43+
try {
44+
headerJson = SignUtils.base64Decode(parts[0]);
45+
payloadJson = SignUtils.base64Decode(parts[1]);
46+
} catch (NullPointerException e) {
47+
throw new JWTDecodeException("The UTF-8 Charset isn't initialized.", e);
48+
}
49+
header = converter.parseHeader(headerJson);
50+
payload = converter.parsePayload(payloadJson);
3451
signature = parts[2];
3552
}
3653

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

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import com.auth0.jwtdecodejava.algorithms.RSAlgorithm;
77
import com.auth0.jwtdecodejava.exceptions.AlgorithmMismatchException;
88
import com.auth0.jwtdecodejava.exceptions.InvalidClaimException;
9-
import com.auth0.jwtdecodejava.exceptions.JWTException;
9+
import com.auth0.jwtdecodejava.exceptions.JWTVerificationException;
1010
import com.auth0.jwtdecodejava.exceptions.SignatureVerificationException;
1111
import com.auth0.jwtdecodejava.impl.PublicClaims;
1212
import com.auth0.jwtdecodejava.interfaces.JWT;
@@ -22,6 +22,9 @@
2222

2323
import static com.auth0.jwtdecodejava.algorithms.NoneAlgorithm.none;
2424

25+
/**
26+
* The JWTVerifier class holds the verify method to assert that a given Token has not only a proper JWT format, but also it's signature matches.
27+
*/
2528
public class JWTVerifier {
2629
private final Algorithm algorithm;
2730
private final String secret;
@@ -35,14 +38,35 @@ private JWTVerifier(Algorithm algorithm, String secret, PublicKey key) {
3538
this.claims = new HashMap<>();
3639
}
3740

38-
public static JWTVerifier init() throws IllegalArgumentException {
41+
/**
42+
* Initialize a JWTVerifier instance using the Algorithm "none".
43+
*
44+
* @return a JWTVerifier instance to configure.
45+
*/
46+
public static JWTVerifier init() {
3947
return init(none, null, null);
4048
}
4149

50+
/**
51+
* Initialize a JWTVerifier instance using a HS Algorithm.
52+
*
53+
* @param algorithm a HSAlgorithm. Valid values are HS256, HS384, HS512.
54+
* @param secret to use when verifying the signature.
55+
* @return a JWTVerifier instance to configure.
56+
* @throws IllegalArgumentException if the provided algorithm is null or if the secret is null.
57+
*/
4258
public static JWTVerifier init(HSAlgorithm algorithm, String secret) throws IllegalArgumentException {
4359
return init(algorithm, null, secret);
4460
}
4561

62+
/**
63+
* Initialize a JWTVerifier instance using a RS Algorithm.
64+
*
65+
* @param algorithm a RSAlgorithm. Valid values are RS256, RS384, RS512.
66+
* @param publicKey to use when verifying the signature.
67+
* @return a JWTVerifier instance to configure.
68+
* @throws IllegalArgumentException if the provided algorithm is null or if the publicKey is null.
69+
*/
4670
public static JWTVerifier init(RSAlgorithm algorithm, PublicKey publicKey) throws IllegalArgumentException {
4771
return init(algorithm, publicKey, null);
4872
}
@@ -60,50 +84,92 @@ private static JWTVerifier init(Algorithm algorithm, PublicKey publicKey, String
6084
return new JWTVerifier(algorithm, secret, publicKey);
6185
}
6286

87+
/**
88+
* Require a specific Issuer ("iss") claim.
89+
*
90+
* @return this same JWTVerifier instance.
91+
*/
6392
public JWTVerifier withIssuer(String issuer) {
6493
requireClaim(PublicClaims.ISSUER, issuer);
6594
return this;
6695
}
6796

97+
/**
98+
* Require a specific Subject ("sub") claim.
99+
*
100+
* @return this same JWTVerifier instance.
101+
*/
68102
public JWTVerifier withSubject(String subject) {
69103
requireClaim(PublicClaims.SUBJECT, subject);
70104
return this;
71105
}
72106

107+
/**
108+
* Require a specific Audience ("aud") claim.
109+
*
110+
* @return this same JWTVerifier instance.
111+
*/
73112
public JWTVerifier withAudience(String[] audience) {
74113
requireClaim(PublicClaims.AUDIENCE, audience);
75114
return this;
76115
}
77116

117+
/**
118+
* Require a specific Expires At ("exp") claim.
119+
*
120+
* @return this same JWTVerifier instance.
121+
*/
78122
public JWTVerifier withExpiresAt(Date expiresAt) {
79123
requireClaim(PublicClaims.EXPIRES_AT, expiresAt);
80124
return this;
81125
}
82126

127+
/**
128+
* Require a specific Not Before ("nbf") claim.
129+
*
130+
* @return this same JWTVerifier instance.
131+
*/
83132
public JWTVerifier withNotBefore(Date notBefore) {
84133
requireClaim(PublicClaims.NOT_BEFORE, notBefore);
85134
return this;
86135
}
87136

137+
/**
138+
* Require a specific Issued At ("iat") claim.
139+
*
140+
* @return this same JWTVerifier instance.
141+
*/
88142
public JWTVerifier withIssuedAt(Date issuedAt) {
89143
requireClaim(PublicClaims.ISSUED_AT, issuedAt);
90144
return this;
91145
}
92146

147+
/**
148+
* Require a specific JWT Id ("jti") claim.
149+
*
150+
* @return this same JWTVerifier instance.
151+
*/
93152
public JWTVerifier withJWTId(String jwtId) {
94153
requireClaim(PublicClaims.JWT_ID, jwtId);
95154
return this;
96155
}
97156

98-
public JWT verify(String token) throws JWTException {
157+
/**
158+
* Perform the verification against the given Token, using any previous configured options.
159+
*
160+
* @param token the String representation of the JWT.
161+
* @return a verified JWT.
162+
* @throws JWTVerificationException if any of the required contents inside the JWT is invalid.
163+
*/
164+
public JWT verify(String token) throws JWTVerificationException {
99165
JWT jwt = JWTDecoder.decode(token);
100166
verifyAlgorithm(jwt, algorithm);
101167
verifySignature(SignUtils.splitToken(token));
102168
verifyClaims(jwt, claims);
103169
return jwt;
104170
}
105171

106-
private void verifySignature(String[] parts) {
172+
private void verifySignature(String[] parts) throws SignatureVerificationException {
107173
if (algorithm instanceof HSAlgorithm) {
108174
try {
109175
SignUtils.verifyHS((HSAlgorithm) algorithm, parts, secret);
@@ -121,7 +187,7 @@ private void verifySignature(String[] parts) {
121187
}
122188
}
123189

124-
private void verifyAlgorithm(JWT jwt, Algorithm expectedAlgorithm) throws AlgorithmMismatchException, IllegalArgumentException {
190+
private void verifyAlgorithm(JWT jwt, Algorithm expectedAlgorithm) throws AlgorithmMismatchException {
125191
if (!expectedAlgorithm.equals(jwt.getAlgorithm())) {
126192
throw new AlgorithmMismatchException("The provided Algorithm doesn't match the one defined in the JWT's Header.");
127193
}
@@ -133,7 +199,7 @@ private void verifyClaims(JWT jwt, Map<String, Object> claims) {
133199
}
134200
}
135201

136-
private void assertValidClaim(JWT jwt, String claimName, Object expectedValue) {
202+
private void assertValidClaim(JWT jwt, String claimName, Object expectedValue) throws InvalidClaimException {
137203
boolean isValid;
138204
if (PublicClaims.AUDIENCE.equals(claimName)) {
139205
isValid = Arrays.equals(jwt.getAudience(), (String[]) expectedValue);

lib/src/main/java/com/auth0/jwtdecodejava/SignUtils.java

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import com.auth0.jwtdecodejava.algorithms.HSAlgorithm;
44
import com.auth0.jwtdecodejava.algorithms.RSAlgorithm;
5-
import com.auth0.jwtdecodejava.exceptions.JWTException;
5+
import com.auth0.jwtdecodejava.exceptions.JWTDecodeException;
66
import org.apache.commons.codec.binary.Base64;
77
import org.apache.commons.codec.binary.StringUtils;
88

@@ -12,38 +12,58 @@
1212

1313
class SignUtils {
1414

15-
static String base64Decode(String string) throws JWTException {
16-
String decoded;
17-
try {
18-
decoded = StringUtils.newStringUtf8(Base64.decodeBase64(string));
19-
} catch (NullPointerException e) {
20-
throw new JWTException("Received bytes didn't correspond to a valid Base64 encoded string.", e);
21-
}
22-
return decoded;
15+
/**
16+
* Decodes a given String from it's Base64 string representation into a UTF-8 String.
17+
*
18+
* @param source the source of the decode process.
19+
* @return a UTF-8 String representing the Base64 decoded source.
20+
* @throws NullPointerException if the UTF-8 Charset isn't initialized.
21+
*/
22+
static String base64Decode(String source) throws NullPointerException {
23+
return StringUtils.newStringUtf8(Base64.decodeBase64(source));
2324
}
2425

25-
static String base64Encode(String string) throws JWTException {
26-
String encoded;
27-
try {
28-
encoded = StringUtils.newStringUtf8(Base64.encodeBase64(string.getBytes(), false, true));
29-
} catch (NullPointerException e) {
30-
throw new JWTException("Received bytes didn't correspond to a valid Base64 encoded string.", e);
31-
}
32-
return encoded;
26+
/**
27+
* Encodes a given String into it's Base64 string representation.
28+
*
29+
* @param source the source of the decode process.
30+
* @return a UTF-8 String encoded into it's Base64 representation.
31+
* @throws NullPointerException if the UTF-8 Charset isn't initialized.
32+
* @throws IllegalArgumentException if the source string is too long.
33+
*/
34+
static String base64Encode(String source) throws NullPointerException, IllegalArgumentException {
35+
return StringUtils.newStringUtf8(Base64.encodeBase64(source.getBytes(), false, true));
3336
}
3437

35-
static String[] splitToken(String token) {
38+
/**
39+
* Splits the given token on the "." chars into a String array with 3 parts.
40+
*
41+
* @param token the string to split.
42+
* @return the array representing the 3 parts of the token.
43+
* @throws JWTDecodeException if the Token doesn't have 3 parts.
44+
*/
45+
static String[] splitToken(String token) throws JWTDecodeException {
3646
String[] parts = token.split("\\.");
3747
if (parts.length == 2 && token.endsWith(".")) {
3848
//Tokens with alg='none' have empty String as Signature.
3949
parts = new String[]{parts[0], parts[1], ""};
4050
}
4151
if (parts.length != 3) {
42-
throw new JWTException(String.format("The token was expected to have 3 parts, but got %s.", parts.length));
52+
throw new JWTDecodeException(String.format("The token was expected to have 3 parts, but got %s.", parts.length));
4353
}
4454
return parts;
4555
}
4656

57+
/**
58+
* Verify the given JWT parts using a specific HS Algorithm and a given secret.
59+
*
60+
* @param algorithm the HSAlgorithm to use. Must be one of HS256, HS384, or HS512.
61+
* @param jwtParts a valid array of size 3 representing the JWT parts.
62+
* @param secret the secret used when signing the token's content.
63+
* @return whether the Token's signature is valid or not.
64+
* @throws NoSuchAlgorithmException if the chosen algorithm isn't present.
65+
* @throws InvalidKeyException
66+
*/
4767
static boolean verifyHS(HSAlgorithm algorithm, String[] jwtParts, String secret) throws NoSuchAlgorithmException, InvalidKeyException {
4868
if (secret == null) {
4969
throw new IllegalArgumentException("The Secret cannot be null");
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
package com.auth0.jwtdecodejava.algorithms;
22

3+
/**
4+
* The Algorithm class represents an algorithm to be used in the Signing or Verification process of a Token.
5+
*/
36
public interface Algorithm {
47

8+
/**
9+
* Getter for the description required when instantiating a Mac or Signature object.
10+
*
11+
* @return the algorithm description.
12+
*/
513
String describe();
614

15+
/**
16+
* Getter for the name of this algorithm as referenced in the JWT standard.
17+
*
18+
* @return the algorithm name.
19+
*/
720
String name();
821

922
}

lib/src/main/java/com/auth0/jwtdecodejava/exceptions/AlgorithmMismatchException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.auth0.jwtdecodejava.exceptions;
22

3-
public class AlgorithmMismatchException extends JWTException{
3+
public class AlgorithmMismatchException extends JWTVerificationException {
44
public AlgorithmMismatchException(String message) {
55
super(message);
66
}

lib/src/main/java/com/auth0/jwtdecodejava/exceptions/InvalidClaimException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.auth0.jwtdecodejava.exceptions;
22

33

4-
public class InvalidClaimException extends JWTException {
4+
public class InvalidClaimException extends JWTVerificationException {
55
public InvalidClaimException(String message) {
66
super(message);
77
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.auth0.jwtdecodejava.exceptions;
2+
3+
public class JWTDecodeException extends RuntimeException {
4+
public JWTDecodeException(String message) {
5+
this(message, null);
6+
}
7+
8+
public JWTDecodeException(String message, Throwable cause) {
9+
super(message, cause);
10+
}
11+
}

lib/src/main/java/com/auth0/jwtdecodejava/exceptions/JWTException.java

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.auth0.jwtdecodejava.exceptions;
2+
3+
public class JWTVerificationException extends RuntimeException {
4+
public JWTVerificationException(String message) {
5+
this(message, null);
6+
}
7+
8+
public JWTVerificationException(String message, Throwable cause) {
9+
super(message, cause);
10+
}
11+
}

0 commit comments

Comments
 (0)