Skip to content

Commit 0071cdf

Browse files
authored
Merge pull request auth0#88 from auth0/better-builders
Wrap decode/verify logic inside a JWT class
2 parents 1b621a2 + 6451016 commit 0071cdf

17 files changed

Lines changed: 729 additions & 110 deletions

File tree

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ language: java
22
jdk:
33
- openjdk7
44
- oraclejdk7
5+
- oraclejdk8
56
before_cache:
67
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
78
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package com.auth0.jwtdecodejava;
2+
3+
import com.auth0.jwtdecodejava.algorithms.Algorithm;
4+
import com.auth0.jwtdecodejava.exceptions.JWTDecodeException;
5+
import com.auth0.jwtdecodejava.interfaces.Claim;
6+
7+
import java.util.Date;
8+
9+
public final class JWT implements com.auth0.jwtdecodejava.interfaces.JWT {
10+
11+
private final com.auth0.jwtdecodejava.interfaces.JWT jwt;
12+
13+
JWT(com.auth0.jwtdecodejava.interfaces.JWT jwt) {
14+
this.jwt = jwt;
15+
}
16+
17+
/**
18+
* Decode a given Token into a JWT instance.
19+
* Note that this method doesn't verify the JWT's signature! Use it only if you trust the issuer of the Token.
20+
*
21+
* @param token the String representation of the JWT.
22+
* @return a decoded JWT.
23+
* @throws JWTDecodeException if any part of the Token contained an invalid JWT or JSON format.
24+
*/
25+
public static JWT decode(String token) throws JWTDecodeException {
26+
return new JWT(JWTDecoder.decode(token));
27+
}
28+
29+
/**
30+
* Creates a Verification instance to configure and verify a Token using the given Algorithm.
31+
*
32+
* @param algorithm the Algorithm to use in JWT verifications.
33+
* @return a Verification instance to configure.
34+
* @throws IllegalArgumentException if the provided algorithm is null.
35+
*/
36+
public static JWTVerifier.Verification require(Algorithm algorithm) throws IllegalArgumentException {
37+
return JWTVerifier.init(algorithm);
38+
}
39+
40+
@Override
41+
public boolean isExpired() {
42+
return jwt.isExpired();
43+
}
44+
45+
@Override
46+
public String getSignature() {
47+
return jwt.getSignature();
48+
}
49+
50+
@Override
51+
public String getIssuer() {
52+
return jwt.getIssuer();
53+
}
54+
55+
@Override
56+
public String getSubject() {
57+
return jwt.getSubject();
58+
}
59+
60+
@Override
61+
public String[] getAudience() {
62+
return jwt.getAudience();
63+
}
64+
65+
@Override
66+
public Date getExpiresAt() {
67+
return jwt.getExpiresAt();
68+
}
69+
70+
@Override
71+
public Date getNotBefore() {
72+
return jwt.getNotBefore();
73+
}
74+
75+
@Override
76+
public Date getIssuedAt() {
77+
return jwt.getIssuedAt();
78+
}
79+
80+
@Override
81+
public String getId() {
82+
return jwt.getId();
83+
}
84+
85+
@Override
86+
public Claim getClaim(String name) {
87+
return jwt.getClaim(name);
88+
}
89+
90+
@Override
91+
public String getAlgorithm() {
92+
return jwt.getAlgorithm();
93+
}
94+
95+
@Override
96+
public String getType() {
97+
return jwt.getType();
98+
}
99+
100+
@Override
101+
public String getContentType() {
102+
return jwt.getContentType();
103+
}
104+
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
/**
1313
* The JWTDecoder class holds the decode method to parse a given Token into it's JWT representation.
1414
*/
15-
public final class JWTDecoder implements JWT {
15+
final class JWTDecoder implements JWT {
1616

1717
private Header header;
1818
private Payload payload;
@@ -30,7 +30,7 @@ private JWTDecoder(String jwt) throws JWTDecodeException {
3030
* @return a decoded JWT.
3131
* @throws JWTDecodeException if any part of the Token contained an invalid JWT or JSON format.
3232
*/
33-
public static JWT decode(String token) throws JWTDecodeException {
33+
static JWT decode(String token) throws JWTDecodeException {
3434
return new JWTDecoder(token);
3535
}
3636

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

Lines changed: 104 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -3,110 +3,137 @@
33
import com.auth0.jwtdecodejava.algorithms.Algorithm;
44
import com.auth0.jwtdecodejava.exceptions.*;
55
import com.auth0.jwtdecodejava.impl.PublicClaims;
6-
import com.auth0.jwtdecodejava.interfaces.JWT;
76

8-
import java.util.Arrays;
9-
import java.util.Date;
10-
import java.util.HashMap;
11-
import java.util.Map;
7+
import java.util.*;
128

139
/**
1410
* 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.
1511
*/
16-
public class JWTVerifier {
12+
class JWTVerifier {
1713
private final Algorithm algorithm;
1814
private final Map<String, Object> claims;
1915

20-
private JWTVerifier(Algorithm algorithm) throws IllegalArgumentException {
21-
if (algorithm == null) {
22-
throw new IllegalArgumentException("The Algorithm cannot be null.");
23-
}
16+
private JWTVerifier(Algorithm algorithm, Map<String, Object> claims) {
2417
this.algorithm = algorithm;
25-
this.claims = new HashMap<>();
18+
this.claims = Collections.unmodifiableMap(claims);
2619
}
2720

2821
/**
2922
* Initialize a JWTVerifier instance using a HS Algorithm.
3023
*
31-
* @param algorithm a HSAlgorithm. Valid values are HS256, HS384, HS512.
24+
* @param algorithm the Algorithm to use on the JWT verification.
3225
* @return a JWTVerifier instance to configure.
33-
* @throws IllegalArgumentException if the provided algorithm is null or if the secret is null.
26+
* @throws IllegalArgumentException if the provided algorithm is null.
3427
*/
35-
public static JWTVerifier init(Algorithm algorithm) throws IllegalArgumentException {
36-
return new JWTVerifier(algorithm);
28+
static JWTVerifier.Verification init(Algorithm algorithm) throws IllegalArgumentException {
29+
return new Verification(algorithm);
3730
}
3831

39-
4032
/**
41-
* Require a specific Issuer ("iss") claim.
42-
*
43-
* @return this same JWTVerifier instance.
33+
* The Verification class holds the Claims required by a JWT to be valid.
4434
*/
45-
public JWTVerifier withIssuer(String issuer) {
46-
requireClaim(PublicClaims.ISSUER, issuer);
47-
return this;
48-
}
35+
static class Verification {
36+
private final Algorithm algorithm;
37+
private final Map<String, Object> claims;
4938

50-
/**
51-
* Require a specific Subject ("sub") claim.
52-
*
53-
* @return this same JWTVerifier instance.
54-
*/
55-
public JWTVerifier withSubject(String subject) {
56-
requireClaim(PublicClaims.SUBJECT, subject);
57-
return this;
58-
}
39+
Verification(Algorithm algorithm) throws IllegalArgumentException {
40+
if (algorithm == null) {
41+
throw new IllegalArgumentException("The Algorithm cannot be null.");
42+
}
5943

60-
/**
61-
* Require a specific Audience ("aud") claim.
62-
*
63-
* @return this same JWTVerifier instance.
64-
*/
65-
public JWTVerifier withAudience(String[] audience) {
66-
requireClaim(PublicClaims.AUDIENCE, audience);
67-
return this;
68-
}
44+
this.algorithm = algorithm;
45+
this.claims = new HashMap<>();
46+
}
6947

70-
/**
71-
* Require a specific Expires At ("exp") claim.
72-
*
73-
* @return this same JWTVerifier instance.
74-
*/
75-
public JWTVerifier withExpiresAt(Date expiresAt) {
76-
requireClaim(PublicClaims.EXPIRES_AT, expiresAt);
77-
return this;
78-
}
48+
/**
49+
* Require a specific Issuer ("iss") claim.
50+
*
51+
* @return this same Verification instance.
52+
*/
53+
public Verification withIssuer(String issuer) {
54+
requireClaim(PublicClaims.ISSUER, issuer);
55+
return this;
56+
}
7957

80-
/**
81-
* Require a specific Not Before ("nbf") claim.
82-
*
83-
* @return this same JWTVerifier instance.
84-
*/
85-
public JWTVerifier withNotBefore(Date notBefore) {
86-
requireClaim(PublicClaims.NOT_BEFORE, notBefore);
87-
return this;
88-
}
58+
/**
59+
* Require a specific Subject ("sub") claim.
60+
*
61+
* @return this same Verification instance.
62+
*/
63+
public Verification withSubject(String subject) {
64+
requireClaim(PublicClaims.SUBJECT, subject);
65+
return this;
66+
}
8967

90-
/**
91-
* Require a specific Issued At ("iat") claim.
92-
*
93-
* @return this same JWTVerifier instance.
94-
*/
95-
public JWTVerifier withIssuedAt(Date issuedAt) {
96-
requireClaim(PublicClaims.ISSUED_AT, issuedAt);
97-
return this;
98-
}
68+
/**
69+
* Require a specific Audience ("aud") claim.
70+
*
71+
* @return this same Verification instance.
72+
*/
73+
public Verification withAudience(String[] audience) {
74+
requireClaim(PublicClaims.AUDIENCE, audience);
75+
return this;
76+
}
9977

100-
/**
101-
* Require a specific JWT Id ("jti") claim.
102-
*
103-
* @return this same JWTVerifier instance.
104-
*/
105-
public JWTVerifier withJWTId(String jwtId) {
106-
requireClaim(PublicClaims.JWT_ID, jwtId);
107-
return this;
78+
/**
79+
* Require a specific Expires At ("exp") claim.
80+
*
81+
* @return this same Verification instance.
82+
*/
83+
public Verification withExpiresAt(Date expiresAt) {
84+
requireClaim(PublicClaims.EXPIRES_AT, expiresAt);
85+
return this;
86+
}
87+
88+
/**
89+
* Require a specific Not Before ("nbf") claim.
90+
*
91+
* @return this same Verification instance.
92+
*/
93+
public Verification withNotBefore(Date notBefore) {
94+
requireClaim(PublicClaims.NOT_BEFORE, notBefore);
95+
return this;
96+
}
97+
98+
/**
99+
* Require a specific Issued At ("iat") claim.
100+
*
101+
* @return this same Verification instance.
102+
*/
103+
public Verification withIssuedAt(Date issuedAt) {
104+
requireClaim(PublicClaims.ISSUED_AT, issuedAt);
105+
return this;
106+
}
107+
108+
/**
109+
* Require a specific JWT Id ("jti") claim.
110+
*
111+
* @return this same Verification instance.
112+
*/
113+
public Verification withJWTId(String jwtId) {
114+
requireClaim(PublicClaims.JWT_ID, jwtId);
115+
return this;
116+
}
117+
118+
/**
119+
* Creates a new and reusable instance of the JWTVerifier with the configuration already provided.
120+
*
121+
* @return a new JWTVerifier instance.
122+
*/
123+
public JWTVerifier build() {
124+
return new JWTVerifier(algorithm, claims);
125+
}
126+
127+
private void requireClaim(String name, Object value) {
128+
if (value == null) {
129+
claims.remove(name);
130+
return;
131+
}
132+
claims.put(name, value);
133+
}
108134
}
109135

136+
110137
/**
111138
* Perform the verification against the given Token, using any previous configured options.
112139
*
@@ -116,7 +143,7 @@ public JWTVerifier withJWTId(String jwtId) {
116143
* @throws JWTVerificationException if any of the required contents inside the JWT is invalid.
117144
*/
118145
public JWT verify(String token) throws JWTDecodeException, JWTVerificationException {
119-
JWT jwt = JWTDecoder.decode(token);
146+
JWT jwt = new JWT(JWTDecoder.decode(token));
120147
verifyAlgorithm(jwt, algorithm);
121148
verifySignature(SignUtils.splitToken(token));
122149
verifyClaims(jwt, claims);
@@ -155,12 +182,4 @@ private void assertValidClaim(JWT jwt, String claimName, Object expectedValue) t
155182
throw new InvalidClaimException(String.format("The Claim '%s' value doesn't match the required one.", claimName));
156183
}
157184
}
158-
159-
private void requireClaim(String name, Object value) {
160-
if (value == null) {
161-
claims.remove(name);
162-
return;
163-
}
164-
claims.put(name, value);
165-
}
166185
}

lib/src/main/java/com/auth0/jwtdecodejava/impl/HeaderImpl.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import com.auth0.jwtdecodejava.interfaces.Header;
44
import com.fasterxml.jackson.databind.JsonNode;
55

6+
import java.util.Collections;
7+
import java.util.HashMap;
68
import java.util.Map;
79

810
import static com.auth0.jwtdecodejava.impl.ClaimImpl.extractClaim;
@@ -15,7 +17,11 @@ class HeaderImpl implements Header {
1517
private final Map<String, JsonNode> tree;
1618

1719
HeaderImpl(Map<String, JsonNode> tree) {
18-
this.tree = tree;
20+
this.tree = Collections.unmodifiableMap(tree == null ? new HashMap<String, JsonNode>() : tree);
21+
}
22+
23+
Map<String, JsonNode> getTree() {
24+
return tree;
1925
}
2026

2127
@Override

0 commit comments

Comments
 (0)