jwt token uses autho 0-jwt framework

Keywords: Java JSON Programming encoding

Links to the original text: http://www.leftso.com/blog/221.html 

Reprint: http://www.leftso.com/blog/221.html Transfer to learning and sharing, and there are other good blog articles for learning.

I. Preface

To use jwt in Java programming, you must first understand what jwt is and what it looks like. If you don't know, you can go to another blog on this site first. What is JWT?
 

jwt Framework Selection in Java Programming

In Java programming, there are many frameworks to implement the JWT standard. The framework used in this blog is the java-jwt version of auth 0, which is 3.2.0.

3. What is Java-JWT

java-jwt of auth0 is an implementation of JSON WEB TOKEN (JWT).

IV. Installation and download-related dependencies

If you use maven, add the following java-jwt dependency fragments to your project pom.xml file:

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.2.0</version>
</dependency>

If you use Gradle, add the following:

compile 'com.auth0:java-jwt:3.2.0'

5. Algorithms already implemented in java-jwt

The library implements JWT verification and signature using the following algorithms:

JWS algorithm introduce
HS256 HMAC256 HMAC with SHA-256
HS384 HMAC384 HMAC with SHA-384
HS512 HMAC512 HMAC with SHA-512
RS256 RSA256 RSASSA-PKCS1-v1_5 with SHA-256
RS384 RSA384 RSASSA-PKCS1-v1_5 with SHA-384
RS512 RSA512 RSASSA-PKCS1-v1_5 with SHA-512
ES256 ECDSA256 ECDSA with curve P-256 and SHA-256
ES384 ECDSA384 ECDSA with curve P-384 and SHA-384
ES512 ECDSA512 ECDSA with curve P-521 and SHA-512

6. How to use java-jwt

6.1. Choose an algorithm

The algorithm defines how a token is signed and verified. It can be instantiated with the original value of HMAC algorithm, or with RSA and ECDSA algorithm, the key pair or key provider can be instantiated. Once created, the instance can be used for token signature and verification operations.

When using RSA or ECDSA algorithms, only signing JWTs can avoid specifying public keys by passing null values. When you need to validate JWTs, you can also use the private key to operate.

Use static character ciphertext or key to get the arithmetic:
 

//HMAC
Algorithm algorithmHS = Algorithm.HMAC256("secret");

//RSA
RSAPublicKey publicKey = //Get the key instance
RSAPrivateKey privateKey = //Get the key instance
Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey);

Use a key provider to obtain the algorithm:
By using KeyProvider, you can change the key at runtime to verify the token signature or to sign a new token for RSA or ECDSA algorithms. This is achieved by implementing RSAKeyProvider or ECDSAKeyProvider methods:

  • getPublicKeyById(String kid): It is called in token signature verification, and it should return the key used to verify the token. If critical rotation is used, such as JWK, it can use id to get the correct rotation key (or just return the same key all the time).
  • getPrivateKey(): Called during the token signature, it should return the key used to sign the JWT.
  • getPrivateKeyId(): Called during token signature, it should return the id identifying the id of the key returned by getPrivateKey(). This value is more popular than the values in the JWTCreator.Builder and keyid(String) methods. If you don't need to set the child's value, avoid using the KeyProvider instantiation algorithm.

The following code snippet shows how to use:

final JwkStore jwkStore = new JwkStore("{JWKS_FILE_HOST}");
final RSAPrivateKey privateKey = //Get the key instance
final String privateKeyId = //Create an Id for the above key

RSAKeyProvider keyProvider = new RSAKeyProvider() {
    @Override
    public RSAPublicKey getPublicKeyById(String kid) {
        //Received 'kid' value might be null if it wasn't defined in the Token's header
        RSAPublicKey publicKey = jwkStore.get(kid);
        return (RSAPublicKey) publicKey;
    }

    @Override
    public RSAPrivateKey getPrivateKey() {
        return privateKey;
    }

    @Override
    public String getPrivateKeyId() {
        return privateKeyId;
    }
};

Algorithm algorithm = Algorithm.RSA256(keyProvider);
//Use the Algorithm to create and verify JWTs.


Tip: For simple key rotation using JWKs, try the JWKs-rsa-java library.

6.2. Create a signed JWT token
First, you need to create a JWTCreator instance by calling jwt.create().

  • For example, HS256 algorithm is used:
try {
    Algorithm algorithm = Algorithm.HMAC256("secret");
    String token = JWT.create()
        .withIssuer("auth0")
        .sign(algorithm);
} catch (UnsupportedEncodingException exception){
    //UTF-8 encoding not supported
} catch (JWTCreationException exception){
    //Invalid Signing configuration / Couldn't convert Claims.
}
  • For example, using RS256 algorithm:
RSAPublicKey publicKey = //Get the key instance
RSAPrivateKey privateKey = //Get the key instance
try {
    Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey);
    String token = JWT.create()
        .withIssuer("auth0")
        .sign(algorithm);
} catch (JWTCreationException exception){
    //Invalid Signing configuration / Couldn't convert Claims.
}

If Claim cannot be converted to JSON or the key used in the signing process is invalid, a JWTCreationException exception will be thrown.

6.3. Authentication token
First, you need to create a JWTVerifier instance by calling jwt.require() and passing algorithm instances. If you require tokens 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 validate different tags. Finally, verifier.verify() is called to verify token.

  • For example, when using HS256 algorithm:
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
try {
    Algorithm algorithm = Algorithm.HMAC256("secret");
    JWTVerifier verifier = JWT.require(algorithm)
        .withIssuer("auth0")
        .build(); //Reusable verifier instance
    DecodedJWT jwt = verifier.verify(token);
} catch (UnsupportedEncodingException exception){
    //UTF-8 encoding not supported
} catch (JWTVerificationException exception){
    //Invalid signature/claims
}
  • For example, when using RS256 algorithm:
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
RSAPublicKey publicKey = //Get the key instance
RSAPrivateKey privateKey = //Get the key instance
try {
    Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey);
    JWTVerifier verifier = JWT.require(algorithm)
        .withIssuer("auth0")
        .build(); //Reusable verifier instance
    DecodedJWT jwt = verifier.verify(token);
} catch (JWTVerificationException exception){
    //Invalid signature/claims
}

If the token has an invalid signature or does not meet Claim's requirements, a JWTVerificationException exception will be thrown

6.4.jwt time verification
The JWT token may include a DataNumber field that can be used for validation:

  • This token issues an expired time of "iat" < TODAY
  • This token has not expired "exp"> TODAY and
  • This token has been used. "nbf"> TODAY

When a token is validated, time validation occurs automatically, resulting in a JWTV erificationException being thrown when the value is invalid. If any of the previous fields are missing, they will not be considered in this validation.
To specify a margin window where tokens are still considered valid, use the accept cyclotron () method in JWTVerifier builder and pass a positive second value. This applies to each of the items listed above.

JWTVerifier verifier = JWT.require(algorithm)
    .acceptLeeway(1) // 1 sec for nbf, iat and exp
    .build();

You can also specify a custom value for a given date declaration and override the default value for that declaration.

JWTVerifier verifier = JWT.require(algorithm)
    .acceptLeeway(1)   //1 sec for nbf and iat
    .acceptExpiresAt(5)   //5 secs for exp
    .build();

If you need to test this behavior in your lib/app, convert the validation instance to basever visualization to obtain the visibility of the verific.build() method, which can accept custom clocks. For example:

BaseVerification verification = (BaseVerification) JWT.require(algorithm)
    .acceptLeeway(1)
    .acceptExpiresAt(5);
Clock clock = new CustomClock(); //Must implement Clock interface
JWTVerifier verifier = verification.build(clock);


6.5 Decoding a jwt token

String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
try {
    DecodedJWT jwt = JWT.decode(token);
} catch (JWTDecodeException exception){
    //Invalid token
}

If the token has an invalid syntax, or the header or payload is not JSONs, a JWTDecodeException exception will be thrown.

6.6JWT Header Resolution


Algorithm ("alg")

Returns the jwt algorithm value or null if not defined

String algorithm = jwt.getAlgorithm();

 

Type ("typ")

Returns the type value of JWT and null if not defined (in most cases the type value is jwt)

String type = jwt.getType();

 

Content Type ("cty")

Returns the type of content, null if not defined

String contentType = jwt.getContentType();


Key Id ("kid")
Returns the id value of key and null if not defined
 

String keyId = jwt.getKeyId();

Private Claims, or custom fields

The additional declaration defined in the token's head can be obtained by calling getHeaderClaim(), which returns even if it cannot be found. You can check whether the declared value is null by calling claim.isNull().

Claim claim = jwt.getHeaderClaim("owner");

When you create a token using jwt.create(), you can specify the header declaration by calling withHeader() and pass the mapping of the declaration at the same time.

Map<String, Object> headerClaims = new HashMap();
headerClaims.put("owner", "auth0");
String token = JWT.create()
        .withHeader(headerClaims)
        .sign(algorithm);

Tip: After the signing process, the alg and typ e values will always be included in the Header.

Payload declaration for 6.7 JWT

Issuer ("iss")

Returns the name value of the issuer and null if not defined in the load

String issuer = jwt.getIssuer();

Subject ("sub")

Returns the user value for which jwt is oriented, and null if not defined in the load

String subject = jwt.getSubject();

Audience ("aud")

Returns who receives the jwt and null if not defined in the load

List<String> audience = jwt.getAudience();

Expiration Time ("exp")

Returns the expiration time of the jwt and null if not defined in the load

Date expiresAt = jwt.getExpiresAt();

Not Before ("nbf")

Returns the Not Before value or null if it's not defined in the Payload.

Date notBefore = jwt.getNotBefore();

Issued At ("iat")

Returns when it was signed and null if it is not defined in the load

Date issuedAt = jwt.getIssuedAt();

JWT ID ("jti")

Returns the unique flag of the jwt and null if not defined in the load

String id = jwt.getId();

Custom declaration
Additional declarations defined in the token payload can be obtained by calling getClaims() or getClaim() and passing the declaration name. Even if the declaration cannot be found, there will be a return value. You can check whether the declared value is null by calling claim.isNull().

Map<String, Claim> claims = jwt.getClaims();    //Key is the Claim name
Claim claim = claims.get("isAdmin");

Or:

Claim claim = jwt.getClaim("isAdmin");

When you create a token using jwt.create(), you can specify a custom declaration by calling withClaim(), passing the name and value at the same time.

String token = JWT.create()
        .withClaim("name", 123)
        .withArrayClaim("array", new Integer[]{1, 2, 3})
        .sign(algorithm);

You can also validate the custom declaration of jwt.require() by calling withClaim(), passing the name and the required value.

JWTVerifier verifier = JWT.require(algorithm)
    .withClaim("name", 123)
    .withArrayClaim("array", 1, 2, 3)
    .build();
DecodedJWT jwt = verifier.verify("my.jwt.token");

Tip: The types of custom JWT declaration creation and validation currently supported are Boolean, Integer, Double, String, Date and Array.

6.8Claim Class
The claim category is the wrapper of the claim value. It allows you to treat claims as different types of classes. Available tools and methods:
Original:

  • asBoolean(): Returns a Boolean value if it cannot be converted back to null.
  • asInt(): Returns an integer value, if it cannot be converted back to null.
  • asDouble(): Returns the Double value and null if it cannot be converted.
  • asLong(): Returns the Long value and null if it cannot be converted.
  • asString(): Returns a String value, or null if it cannot be converted.
  • asDate(): Returns the Date value and null if it cannot be converted. Must be a digital date (Unix system timestamp). Note that the JWT standard specifies that all digital date values must be in seconds.

Custom types and collections:

To get the declaration as a collection, you need to provide the class type of the content to be transformed

  • as(class): Returns the parsed value of Class Type. For collections, you should use the asArray and asList methods.
  • asMap(): Returns the value converted to Map < String, Object >
  • asArray(class): Returns the Class Type converted to the element type, or null if the value is not't a JSON Array.
  • asList(class): Returns the Class Type of the collection element, or null if the value is not't a JSON Array.

If the value cannot be converted to a given class type, a JWTDecodeException exception is thrown

Posted by Froy on Mon, 09 Sep 2019 23:45:12 -0700