Skip to content

Commit f7d5cf2

Browse files
committed
add JWTCreator. Add token signing with every algorithm
1 parent 8b3fbd2 commit f7d5cf2

9 files changed

Lines changed: 364 additions & 49 deletions

File tree

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@ public static JWTVerifier.Verification require(Algorithm algorithm) throws Illeg
3737
return JWTVerifier.init(algorithm);
3838
}
3939

40+
/**
41+
* Creates a Builder instance to configure and construct a Token using the given Algorithm.
42+
*
43+
* @param algorithm the Algorithm to use in JWT signing.
44+
* @return a Builder instance to configure.
45+
* @throws IllegalArgumentException if the provided algorithm is null.
46+
*/
47+
public static JWTCreator.Builder create(Algorithm algorithm) throws IllegalArgumentException {
48+
return JWTCreator.init(algorithm);
49+
}
50+
4051
@Override
4152
public String getSignature() {
4253
return jwt.getSignature();
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package com.auth0.jwt;
2+
3+
import com.auth0.jwt.algorithms.Algorithm;
4+
import com.auth0.jwt.exceptions.JWTCreationException;
5+
import com.auth0.jwt.exceptions.SignatureGenerationException;
6+
import com.auth0.jwt.impl.PublicClaims;
7+
import com.fasterxml.jackson.core.JsonProcessingException;
8+
import com.fasterxml.jackson.databind.ObjectMapper;
9+
10+
import java.util.Collections;
11+
import java.util.Date;
12+
import java.util.HashMap;
13+
import java.util.Map;
14+
15+
class JWTCreator {
16+
17+
private final Algorithm algorithm;
18+
private final String headerJson;
19+
private final String payloadJson;
20+
21+
private JWTCreator(Algorithm algorithm, Map<String, Object> headerClaims, Map<String, Object> payloadClaims) throws JWTCreationException {
22+
this.algorithm = algorithm;
23+
headerClaims.put(PublicClaims.ALGORITHM, algorithm.getName());
24+
try {
25+
headerJson = toSafeJson(headerClaims);
26+
payloadJson = toSafeJson(payloadClaims);
27+
} catch (JsonProcessingException e) {
28+
throw new JWTCreationException("Some of the Claims couldn't be converted to a valid JSON format.", e);
29+
}
30+
}
31+
32+
33+
/**
34+
* Initialize a JWTCreator instance using the given Algorithm.
35+
*
36+
* @param algorithm the Algorithm to use on the JWT signing.
37+
* @return a JWTCreator.Builder instance to configure.
38+
* @throws IllegalArgumentException if the provided algorithm is null.
39+
*/
40+
static JWTCreator.Builder init(Algorithm algorithm) throws IllegalArgumentException {
41+
return new Builder(algorithm);
42+
}
43+
44+
/**
45+
* The Builder class holds the Claims required by a JWT to be valid.
46+
*/
47+
static class Builder {
48+
private final Algorithm algorithm;
49+
private final Map<String, Object> payloadClaims;
50+
private Map<String, Object> headerClaims;
51+
52+
Builder(Algorithm algorithm) throws IllegalArgumentException {
53+
if (algorithm == null) {
54+
throw new IllegalArgumentException("The Algorithm cannot be null.");
55+
}
56+
57+
this.algorithm = algorithm;
58+
this.payloadClaims = new HashMap<>();
59+
this.headerClaims = new HashMap<>();
60+
}
61+
62+
/**
63+
* Add specific Claims to set as the Header.
64+
*
65+
* @return this same Builder instance.
66+
*/
67+
public Builder withHeader(Map<String, Object> headerClaims) {
68+
this.headerClaims = Collections.unmodifiableMap(headerClaims);
69+
return this;
70+
}
71+
72+
/**
73+
* Add a specific Issuer ("iss") claim.
74+
*
75+
* @return this same Builder instance.
76+
*/
77+
public Builder withIssuer(String issuer) {
78+
addClaim(PublicClaims.ISSUER, issuer);
79+
return this;
80+
}
81+
82+
/**
83+
* Add a specific Subject ("sub") claim.
84+
*
85+
* @return this same Builder instance.
86+
*/
87+
public Builder withSubject(String subject) {
88+
addClaim(PublicClaims.SUBJECT, subject);
89+
return this;
90+
}
91+
92+
/**
93+
* Add a specific Audience ("aud") claim.
94+
*
95+
* @return this same Builder instance.
96+
*/
97+
public Builder withAudience(String[] audience) {
98+
addClaim(PublicClaims.AUDIENCE, audience);
99+
return this;
100+
}
101+
102+
/**
103+
* Add a specific Expires At ("exp") claim.
104+
*
105+
* @return this same Builder instance.
106+
*/
107+
public Builder withExpiresAt(Date expiresAt) {
108+
addClaim(PublicClaims.EXPIRES_AT, expiresAt);
109+
return this;
110+
}
111+
112+
/**
113+
* Add a specific Not Before ("nbf") claim.
114+
*
115+
* @return this same Builder instance.
116+
*/
117+
public Builder withNotBefore(Date notBefore) {
118+
addClaim(PublicClaims.NOT_BEFORE, notBefore);
119+
return this;
120+
}
121+
122+
/**
123+
* Add a specific Issued At ("iat") claim.
124+
*
125+
* @return this same Builder instance.
126+
*/
127+
public Builder withIssuedAt(Date issuedAt) {
128+
addClaim(PublicClaims.ISSUED_AT, issuedAt);
129+
return this;
130+
}
131+
132+
/**
133+
* Add a specific JWT Id ("jti") claim.
134+
*
135+
* @return this same Builder instance.
136+
*/
137+
public Builder withJWTId(String jwtId) {
138+
addClaim(PublicClaims.JWT_ID, jwtId);
139+
return this;
140+
}
141+
142+
/**
143+
* Creates a new instance of the JWT with the specified payloadClaims.
144+
*
145+
* @return a new JWT instance.
146+
*/
147+
public String sign() throws JWTCreationException {
148+
return new JWTCreator(algorithm, headerClaims, payloadClaims).sign();
149+
}
150+
151+
private void addClaim(String name, Object value) {
152+
if (value == null) {
153+
payloadClaims.remove(name);
154+
return;
155+
}
156+
payloadClaims.put(name, value);
157+
}
158+
}
159+
160+
private String toSafeJson(Map<String, Object> claims) throws JsonProcessingException {
161+
ObjectMapper mapper = new ObjectMapper();
162+
return mapper.writeValueAsString(claims);
163+
}
164+
165+
private String sign() throws SignatureGenerationException {
166+
String header = SignUtils.base64Encode(headerJson.getBytes());
167+
String payload = SignUtils.base64Encode(payloadJson.getBytes());
168+
String content = String.format("%s.%s", header, payload);
169+
170+
byte[] signatureBytes = algorithm.sign(content.getBytes());
171+
String signature = SignUtils.base64Encode(signatureBytes);
172+
173+
return String.format("%s.%s", content, signature);
174+
}
175+
}

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

Lines changed: 0 additions & 18 deletions
This file was deleted.

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ private JWTVerifier(Algorithm algorithm, Map<String, Object> claims, Clock clock
2121
}
2222

2323
/**
24-
* Initialize a JWTVerifier instance using a HS Algorithm.
24+
* Initialize a JWTVerifier instance using the given Algorithm.
2525
*
2626
* @param algorithm the Algorithm to use on the JWT verification.
27-
* @return a JWTVerifier instance to configure.
27+
* @return a JWTVerifier.Verification instance to configure.
2828
* @throws IllegalArgumentException if the provided algorithm is null.
2929
*/
3030
static JWTVerifier.Verification init(Algorithm algorithm) throws IllegalArgumentException {

lib/src/main/java/com/auth0/jwt/impl/PublicClaims.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
public abstract class PublicClaims {
55

66
//Header
7-
static final String ALGORITHM = "alg";
7+
public static final String ALGORITHM = "alg";
88
static final String CONTENT_TYPE = "cty";
99
static final String TYPE = "typ";
1010

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

Lines changed: 0 additions & 28 deletions
This file was deleted.

0 commit comments

Comments
 (0)