Skip to content

Commit aa5ff04

Browse files
authored
Merge pull request auth0#147 from auth0/accept-both-keys
Instantiate RSA/EC Algorithm with both keys
2 parents 2bf84e0 + c4f2094 commit aa5ff04

File tree

7 files changed

+625
-191
lines changed

7 files changed

+625
-191
lines changed

README.md

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
A Java implementation of [JSON Web Tokens (draft-ietf-oauth-json-web-token-08)](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html).
1010

11-
If you're looking for an *Android* version of the JWT Decoder take a look at our [JWTDecode.Android](https://github.com/auth0/JWTDecode.Android) library.
11+
If you're looking for an **Android** version of the JWT Decoder take a look at our [JWTDecode.Android](https://github.com/auth0/JWTDecode.Android) library.
1212

1313
## Installation
1414

@@ -48,15 +48,18 @@ The library implements JWT Verification and Signing using the following algorith
4848

4949
### Create and Sign a Token
5050

51-
You'll first need to create a `JWTCreator` instance by calling `JWT.create()`. Use the builder to define the custom Claims your token needs to have. Finally to get the String token call `sign()` and pass the Algorithm instance.
51+
You'll first need to create a `JWTCreator` instance by calling `JWT.create()`. Use the builder to define the custom Claims your token needs to have. Finally to get the String token call `sign()` and pass the `Algorithm` instance.
5252

5353
* Example using `HS256`
5454

5555
```java
5656
try {
57+
Algorithm algorithm = Algorithm.HMAC256("secret");
5758
String token = JWT.create()
5859
.withIssuer("auth0")
59-
.sign(Algorithm.HMAC256("secret"));
60+
.sign(algorithm);
61+
} catch (UnsupportedEncodingException exception){
62+
//UTF-8 encoding not supported
6063
} catch (JWTCreationException exception){
6164
//Invalid Signing configuration / Couldn't convert Claims.
6265
}
@@ -65,11 +68,13 @@ try {
6568
* Example using `RS256`
6669

6770
```java
68-
PrivateKey key = //Get the key instance
71+
RSAPublicKey publicKey = //Get the key instance
72+
RSAPrivateKey privateKey = //Get the key instance
6973
try {
74+
Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey);
7075
String token = JWT.create()
7176
.withIssuer("auth0")
72-
.sign(Algorithm.RSA256(key));
77+
.sign(algorithm);
7378
} catch (JWTCreationException exception){
7479
//Invalid Signing configuration / Couldn't convert Claims.
7580
}
@@ -80,17 +85,20 @@ If a Claim couldn't be converted to JSON or the Key used in the signing process
8085

8186
### Verify a Token
8287

83-
You'll first need to create a `JWTVerifier` instance by calling `JWT.require()` and passing the Algorithm instance. If you require the token to have specific Claim values, use the builder to define them. The instance returned by the method `build()` is reusable, so you can define it once and use it to verify different tokens. Finally call `verifier.verify()` passing the token.
88+
You'll first need to create a `JWTVerifier` instance by calling `JWT.require()` and passing the `Algorithm` instance. If you require the token to have specific Claim values, use the builder to define them. The instance returned by the method `build()` is reusable, so you can define it once and use it to verify different tokens. Finally call `verifier.verify()` passing the token.
8489

8590
* Example using `HS256`
8691

8792
```java
8893
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
8994
try {
90-
JWTVerifier verifier = JWT.require(Algorithm.HMAC256("secret"))
95+
Algorithm algorithm = Algorithm.HMAC256("secret");
96+
JWTVerifier verifier = JWT.require(algorithm)
9197
.withIssuer("auth0")
9298
.build(); //Reusable verifier instance
9399
DecodedJWT jwt = verifier.verify(token);
100+
} catch (UnsupportedEncodingException exception){
101+
//UTF-8 encoding not supported
94102
} catch (JWTVerificationException exception){
95103
//Invalid signature/claims
96104
}
@@ -100,9 +108,11 @@ try {
100108

101109
```java
102110
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
103-
PublicKey key = //Get the key instance
111+
RSAPublicKey publicKey = //Get the key instance
112+
RSAPrivateKey privateKey = //Get the key instance
104113
try {
105-
JWTVerifier verifier = JWT.require(Algorithm.RSA256(key))
114+
Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey);
115+
JWTVerifier verifier = JWT.require(algorithm)
106116
.withIssuer("auth0")
107117
.build(); //Reusable verifier instance
108118
DecodedJWT jwt = verifier.verify(token);
@@ -126,15 +136,15 @@ When verifying a token the time validation occurs automatically, resulting in a
126136
To specify a **leeway window** in which the Token should still be considered valid, use the `acceptLeeway()` method in the `JWTVerifier` builder and pass a positive seconds value. This applies to every item listed above.
127137

128138
```java
129-
JWTVerifier verifier = JWT.require(Algorithm.RSA256(key))
139+
JWTVerifier verifier = JWT.require(algorithm)
130140
.acceptLeeway(1) // 1 sec for nbf, iat and exp
131141
.build();
132142
```
133143

134144
You can also specify a custom value for a given Date claim and override the default one for only that claim.
135145

136146
```java
137-
JWTVerifier verifier = JWT.require(Algorithm.RSA256(key))
147+
JWTVerifier verifier = JWT.require(algorithm)
138148
.acceptLeeway(1) //1 sec for nbf and iat
139149
.acceptExpiresAt(5) //5 secs for exp
140150
.build();
@@ -143,7 +153,7 @@ JWTVerifier verifier = JWT.require(Algorithm.RSA256(key))
143153
If you need to test this behaviour in your lib/app cast the `Verification` instance to a `BaseVerification` to gain visibility of the `verification.build()` method that accepts a custom `Clock`. e.g.:
144154

145155
```java
146-
BaseVerification verification = (BaseVerification) JWT.require(Algorithm.RSA256(key))
156+
BaseVerification verification = (BaseVerification) JWT.require(algorithm)
147157
.acceptLeeway(1)
148158
.acceptExpiresAt(5);
149159
Clock clock = new CustomClock(); //Must implement Clock interface
@@ -211,9 +221,9 @@ When creating a Token with the `JWT.create()` you can specify header Claims by c
211221
```java
212222
Map<String, Object> headerClaims = new HashMap();
213223
headerclaims.put("owner", "auth0");
214-
JWT.create()
215-
.withHeader(headerClaims)
216-
.sign(Algorithm.HMAC256("secret"));
224+
String token = JWT.create()
225+
.withHeader(headerClaims)
226+
.sign(algorithm);
217227
```
218228

219229
> The `alg` and `typ` values will always be included in the Header after the signing process.
@@ -295,20 +305,20 @@ Claim claim = jwt.getClaim("isAdmin");
295305
When creating a Token with the `JWT.create()` you can specify a custom Claim by calling `withClaim()` and passing both the name and the value.
296306

297307
```java
298-
JWT.create()
299-
.withClaim("name", 123)
300-
.withArrayClaim("array", new Integer[]{1, 2, 3})
301-
.sign(Algorithm.HMAC256("secret"));
308+
String token = JWT.create()
309+
.withClaim("name", 123)
310+
.withArrayClaim("array", new Integer[]{1, 2, 3})
311+
.sign(algorithm);
302312
```
303313

304314
You can also verify custom Claims on the `JWT.require()` by calling `withClaim()` and passing both the name and the required value.
305315

306316
```java
307-
JWT.require(Algorithm.HMAC256("secret"))
317+
JWTVerifier verifier = JWT.require(algorithm)
308318
.withClaim("name", 123)
309319
.withArrayClaim("array", 1, 2, 3)
310-
.build()
311-
.verify("my.jwt.token");
320+
.build();
321+
DecodedJWT jwt = verifier.verify("my.jwt.token");
312322
```
313323

314324
> Currently supported classes for custom JWT Claim creation and verification are: Boolean, Integer, Double, String, Date and Arrays of type String and Integer.

lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java

Lines changed: 104 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
import com.auth0.jwt.exceptions.SignatureVerificationException;
55

66
import java.io.UnsupportedEncodingException;
7-
import java.security.interfaces.ECKey;
8-
import java.security.interfaces.RSAKey;
7+
import java.security.interfaces.*;
98

109
/**
1110
* The Algorithm class represents an algorithm to be used in the Signing or Verification process of a Token.
1211
*/
12+
@SuppressWarnings("WeakerAccess")
1313
public abstract class Algorithm {
1414

1515
private final String name;
@@ -21,9 +21,13 @@ public abstract class Algorithm {
2121
* @param key the key to use in the verify or signing instance.
2222
* @return a valid RSA256 Algorithm.
2323
* @throws IllegalArgumentException if the provided Key is null.
24+
* @deprecated use {@link #RSA256(RSAPublicKey, RSAPrivateKey)}
2425
*/
26+
@Deprecated
2527
public static Algorithm RSA256(RSAKey key) throws IllegalArgumentException {
26-
return new RSAAlgorithm("RS256", "SHA256withRSA", key);
28+
RSAPublicKey publicKey = key instanceof RSAPublicKey ? (RSAPublicKey) key : null;
29+
RSAPrivateKey privateKey = key instanceof RSAPrivateKey ? (RSAPrivateKey) key : null;
30+
return RSA256(publicKey, privateKey);
2731
}
2832

2933
/**
@@ -32,9 +36,13 @@ public static Algorithm RSA256(RSAKey key) throws IllegalArgumentException {
3236
* @param key the key to use in the verify or signing instance.
3337
* @return a valid RSA384 Algorithm.
3438
* @throws IllegalArgumentException if the provided Key is null.
39+
* @deprecated use {@link #RSA384(RSAPublicKey, RSAPrivateKey)}
3540
*/
41+
@Deprecated
3642
public static Algorithm RSA384(RSAKey key) throws IllegalArgumentException {
37-
return new RSAAlgorithm("RS384", "SHA384withRSA", key);
43+
RSAPublicKey publicKey = key instanceof RSAPublicKey ? (RSAPublicKey) key : null;
44+
RSAPrivateKey privateKey = key instanceof RSAPrivateKey ? (RSAPrivateKey) key : null;
45+
return RSA384(publicKey, privateKey);
3846
}
3947

4048
/**
@@ -43,9 +51,49 @@ public static Algorithm RSA384(RSAKey key) throws IllegalArgumentException {
4351
* @param key the key to use in the verify or signing instance.
4452
* @return a valid RSA512 Algorithm.
4553
* @throws IllegalArgumentException if the provided Key is null.
54+
* @deprecated use {@link #RSA512(RSAPublicKey, RSAPrivateKey)}
4655
*/
56+
@Deprecated
4757
public static Algorithm RSA512(RSAKey key) throws IllegalArgumentException {
48-
return new RSAAlgorithm("RS512", "SHA512withRSA", key);
58+
RSAPublicKey publicKey = key instanceof RSAPublicKey ? (RSAPublicKey) key : null;
59+
RSAPrivateKey privateKey = key instanceof RSAPrivateKey ? (RSAPrivateKey) key : null;
60+
return RSA512(publicKey, privateKey);
61+
}
62+
63+
/**
64+
* Creates a new Algorithm instance using SHA256withRSA. Tokens specify this as "RS256".
65+
*
66+
* @param publicKey the key to use in the verify instance.
67+
* @param privateKey the key to use in the signing instance.
68+
* @return a valid RSA256 Algorithm.
69+
* @throws IllegalArgumentException if both provided Keys are null.
70+
*/
71+
public static Algorithm RSA256(RSAPublicKey publicKey, RSAPrivateKey privateKey) throws IllegalArgumentException {
72+
return new RSAAlgorithm("RS256", "SHA256withRSA", publicKey, privateKey);
73+
}
74+
75+
/**
76+
* Creates a new Algorithm instance using SHA384withRSA. Tokens specify this as "RS384".
77+
*
78+
* @param publicKey the key to use in the verify instance.
79+
* @param privateKey the key to use in the signing instance.
80+
* @return a valid RSA384 Algorithm.
81+
* @throws IllegalArgumentException if both provided Keys are null.
82+
*/
83+
public static Algorithm RSA384(RSAPublicKey publicKey, RSAPrivateKey privateKey) throws IllegalArgumentException {
84+
return new RSAAlgorithm("RS384", "SHA384withRSA", publicKey, privateKey);
85+
}
86+
87+
/**
88+
* Creates a new Algorithm instance using SHA512withRSA. Tokens specify this as "RS512".
89+
*
90+
* @param publicKey the key to use in the verify instance.
91+
* @param privateKey the key to use in the signing instance.
92+
* @return a valid RSA512 Algorithm.
93+
* @throws IllegalArgumentException if both provided Keys are null.
94+
*/
95+
public static Algorithm RSA512(RSAPublicKey publicKey, RSAPrivateKey privateKey) throws IllegalArgumentException {
96+
return new RSAAlgorithm("RS512", "SHA512withRSA", publicKey, privateKey);
4997
}
5098

5199
/**
@@ -123,9 +171,13 @@ public static Algorithm HMAC512(byte[] secret) throws IllegalArgumentException {
123171
* @param key the key to use in the verify or signing instance.
124172
* @return a valid ECDSA256 Algorithm.
125173
* @throws IllegalArgumentException if the provided Key is null.
174+
* @deprecated use {@link #ECDSA256(ECPublicKey, ECPrivateKey)}
126175
*/
176+
@Deprecated
127177
public static Algorithm ECDSA256(ECKey key) throws IllegalArgumentException {
128-
return new ECDSAAlgorithm("ES256", "SHA256withECDSA", 32, key);
178+
ECPublicKey publicKey = key instanceof ECPublicKey ? (ECPublicKey) key : null;
179+
ECPrivateKey privateKey = key instanceof ECPrivateKey ? (ECPrivateKey) key : null;
180+
return ECDSA256(publicKey, privateKey);
129181
}
130182

131183
/**
@@ -134,9 +186,13 @@ public static Algorithm ECDSA256(ECKey key) throws IllegalArgumentException {
134186
* @param key the key to use in the verify or signing instance.
135187
* @return a valid ECDSA384 Algorithm.
136188
* @throws IllegalArgumentException if the provided Key is null.
189+
* @deprecated use {@link #ECDSA384(ECPublicKey, ECPrivateKey)}
137190
*/
191+
@Deprecated
138192
public static Algorithm ECDSA384(ECKey key) throws IllegalArgumentException {
139-
return new ECDSAAlgorithm("ES384", "SHA384withECDSA", 48, key);
193+
ECPublicKey publicKey = key instanceof ECPublicKey ? (ECPublicKey) key : null;
194+
ECPrivateKey privateKey = key instanceof ECPrivateKey ? (ECPrivateKey) key : null;
195+
return ECDSA384(publicKey, privateKey);
140196
}
141197

142198
/**
@@ -145,9 +201,49 @@ public static Algorithm ECDSA384(ECKey key) throws IllegalArgumentException {
145201
* @param key the key to use in the verify or signing instance.
146202
* @return a valid ECDSA512 Algorithm.
147203
* @throws IllegalArgumentException if the provided Key is null.
204+
* @deprecated use {@link #ECDSA512(ECPublicKey, ECPrivateKey)}
148205
*/
206+
@Deprecated
149207
public static Algorithm ECDSA512(ECKey key) throws IllegalArgumentException {
150-
return new ECDSAAlgorithm("ES512", "SHA512withECDSA", 66, key);
208+
ECPublicKey publicKey = key instanceof ECPublicKey ? (ECPublicKey) key : null;
209+
ECPrivateKey privateKey = key instanceof ECPrivateKey ? (ECPrivateKey) key : null;
210+
return ECDSA512(publicKey, privateKey);
211+
}
212+
213+
/**
214+
* Creates a new Algorithm instance using SHA256withECDSA. Tokens specify this as "ES256".
215+
*
216+
* @param publicKey the key to use in the verify instance.
217+
* @param privateKey the key to use in the signing instance.
218+
* @return a valid ECDSA256 Algorithm.
219+
* @throws IllegalArgumentException if the provided Key is null.
220+
*/
221+
public static Algorithm ECDSA256(ECPublicKey publicKey, ECPrivateKey privateKey) throws IllegalArgumentException {
222+
return new ECDSAAlgorithm("ES256", "SHA256withECDSA", 32, publicKey, privateKey);
223+
}
224+
225+
/**
226+
* Creates a new Algorithm instance using SHA384withECDSA. Tokens specify this as "ES384".
227+
*
228+
* @param publicKey the key to use in the verify instance.
229+
* @param privateKey the key to use in the signing instance.
230+
* @return a valid ECDSA384 Algorithm.
231+
* @throws IllegalArgumentException if the provided Key is null.
232+
*/
233+
public static Algorithm ECDSA384(ECPublicKey publicKey, ECPrivateKey privateKey) throws IllegalArgumentException {
234+
return new ECDSAAlgorithm("ES384", "SHA384withECDSA", 48, publicKey, privateKey);
235+
}
236+
237+
/**
238+
* Creates a new Algorithm instance using SHA512withECDSA. Tokens specify this as "ES512".
239+
*
240+
* @param publicKey the key to use in the verify instance.
241+
* @param privateKey the key to use in the signing instance.
242+
* @return a valid ECDSA512 Algorithm.
243+
* @throws IllegalArgumentException if the provided Key is null.
244+
*/
245+
public static Algorithm ECDSA512(ECPublicKey publicKey, ECPrivateKey privateKey) throws IllegalArgumentException {
246+
return new ECDSAAlgorithm("ES512", "SHA512withECDSA", 66, publicKey, privateKey);
151247
}
152248

153249
public static Algorithm none() {

0 commit comments

Comments
 (0)