From 0f14a631abbf0cc0210430ee13e7f1fcc7e06310 Mon Sep 17 00:00:00 2001 From: LiamGve Date: Sun, 14 Mar 2021 00:12:16 +0000 Subject: [PATCH] Bael 4805 Decode a JWT Token in Java (#10535) * BAEL-4805 Added the code for Decoding a JWT Token in Java tutorial * BAEL-4805 Added newline at end of test file to conform to standards * BAEL-4805 renamed test class to conform to naming standard for unit tests * BAEL-4805 removed @DisplayName annotations as they are redundant * BAEL-4805 changed assertion to be the user name in payload section to be more meaningful to reader Co-authored-by: Liam Garvie --- jjwt/pom.xml | 6 +++ .../jjwtfun/util/JWTDecoderUtil.java | 46 +++++++++++++++++++ .../jjwtfun/util/JWTDecoderUtilUnitTest.java | 32 +++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 jjwt/src/main/java/io/jsonwebtoken/jjwtfun/util/JWTDecoderUtil.java create mode 100644 jjwt/src/test/java/io/jsonwebtoken/jjwtfun/util/JWTDecoderUtilUnitTest.java diff --git a/jjwt/pom.xml b/jjwt/pom.xml index aa238fafb5..9d38d1b0e9 100644 --- a/jjwt/pom.xml +++ b/jjwt/pom.xml @@ -41,6 +41,12 @@ jjwt ${jjwt.version} + + + org.assertj + assertj-core + test + diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/util/JWTDecoderUtil.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/util/JWTDecoderUtil.java new file mode 100644 index 0000000000..922d5c0ce5 --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/util/JWTDecoderUtil.java @@ -0,0 +1,46 @@ +package io.jsonwebtoken.jjwtfun.util; + +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.impl.crypto.DefaultJwtSignatureValidator; + +import javax.crypto.spec.SecretKeySpec; +import java.util.Base64; + +import static io.jsonwebtoken.SignatureAlgorithm.HS256; + +public class JWTDecoderUtil { + + public static String decodeJWTToken(String token) { + Base64.Decoder decoder = Base64.getDecoder(); + + String[] chunks = token.split("\\."); + + String header = new String(decoder.decode(chunks[0])); + String payload = new String(decoder.decode(chunks[1])); + + return header + " " + payload; + } + + public static String decodeJWTToken(String token, String secretKey) throws Exception { + Base64.Decoder decoder = Base64.getDecoder(); + + String[] chunks = token.split("\\."); + + String header = new String(decoder.decode(chunks[0])); + String payload = new String(decoder.decode(chunks[1])); + + String tokenWithoutSignature = chunks[0] + "." + chunks[1]; + String signature = chunks[2]; + + SignatureAlgorithm sa = HS256; + SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), sa.getJcaName()); + + DefaultJwtSignatureValidator validator = new DefaultJwtSignatureValidator(sa, secretKeySpec); + + if (!validator.isValid(tokenWithoutSignature, signature)) { + throw new Exception("Could not verify JWT token integrity!"); + } + + return header + " " + payload; + } +} diff --git a/jjwt/src/test/java/io/jsonwebtoken/jjwtfun/util/JWTDecoderUtilUnitTest.java b/jjwt/src/test/java/io/jsonwebtoken/jjwtfun/util/JWTDecoderUtilUnitTest.java new file mode 100644 index 0000000000..3103a6c8a3 --- /dev/null +++ b/jjwt/src/test/java/io/jsonwebtoken/jjwtfun/util/JWTDecoderUtilUnitTest.java @@ -0,0 +1,32 @@ +package io.jsonwebtoken.jjwtfun.util; + +import io.jsonwebtoken.SignatureAlgorithm; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class JWTDecoderUtilUnitTest { + + private final static String SIMPLE_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkJhZWxkdW5nIFVzZXIiLCJpYXQiOjE1MTYyMzkwMjJ9"; + private final static String SIGNED_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkJhZWxkdW5nIFVzZXIiLCJpYXQiOjE1MTYyMzkwMjJ9.qH7Zj_m3kY69kxhaQXTa-ivIpytKXXjZc1ZSmapZnGE"; + + @Test + void givenSimpleToken_whenDecoding_thenStringOfHeaderPayloadAreReturned() { + assertThat(JWTDecoderUtil.decodeJWTToken(SIMPLE_TOKEN)) + .contains(SignatureAlgorithm.HS256.getValue()); + } + + @Test + void givenSignedToken_whenDecodingWithInvalidSecret_thenIntegrityIsNotValidated() { + assertThatThrownBy(() -> JWTDecoderUtil.decodeJWTToken(SIGNED_TOKEN, "BAD_SECRET")) + .hasMessage("Could not verify JWT token integrity!"); + } + + @Test + void givenSignedToken_whenDecodingWithValidSecret_thenIntegrityIsValidated() throws Exception { + assertThat(JWTDecoderUtil.decodeJWTToken(SIGNED_TOKEN, "MySecretKey")) + .contains("Baeldung User"); + } +}