diff --git a/security-modules/jwt/.gitignore b/security-modules/jwt/.gitignore
new file mode 100644
index 0000000000..f83e8cf07c
--- /dev/null
+++ b/security-modules/jwt/.gitignore
@@ -0,0 +1,3 @@
+.idea
+target
+*.iml
diff --git a/security-modules/jwt/pom.xml b/security-modules/jwt/pom.xml
new file mode 100644
index 0000000000..5ec563dcfa
--- /dev/null
+++ b/security-modules/jwt/pom.xml
@@ -0,0 +1,28 @@
+
+
+ 4.0.0
+ jwt
+ jwt
+ jar
+
+
+ com.baeldung
+ security-modules
+ 1.0.0-SNAPSHOT
+
+
+
+
+ com.auth0
+ java-jwt
+ ${auth0-jwt.version}
+
+
+
+
+ 4.2.1
+
+
+
\ No newline at end of file
diff --git a/security-modules/jwt/src/main/java/com/baeldung/jwt/auth0/Auth0JsonWebToken.java b/security-modules/jwt/src/main/java/com/baeldung/jwt/auth0/Auth0JsonWebToken.java
new file mode 100644
index 0000000000..0d5e7a4839
--- /dev/null
+++ b/security-modules/jwt/src/main/java/com/baeldung/jwt/auth0/Auth0JsonWebToken.java
@@ -0,0 +1,99 @@
+package com.baeldung.jwt.auth0;
+
+import java.util.Date;
+import java.util.UUID;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTVerifier;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.JWTVerificationException;
+import com.auth0.jwt.interfaces.Claim;
+import com.auth0.jwt.interfaces.DecodedJWT;
+
+public class Auth0JsonWebToken {
+
+ private static final String SECRET = "baeldung";
+ private static final String ISSUER = "Baeldung";
+ private static final String SUBJECT = "Baeldung Details";
+ private static final String DATA_CLAIM = "userId";
+ private static final String DATA = "1234";
+ private static final long TOKEN_VALIDITY_IN_MILLIS = 5000L;
+
+ private static Algorithm algorithm;
+ private static JWTVerifier verifier;
+
+ public static void initialize() {
+ algorithm = Algorithm.HMAC256(SECRET);
+
+ verifier = JWT.require(algorithm)
+ .withIssuer(ISSUER)
+ .build();
+ }
+
+ private static String createJWT() {
+ String jwtToken = JWT.create()
+ .withIssuer(ISSUER)
+ .withSubject(SUBJECT)
+ .withClaim(DATA_CLAIM, DATA)
+ .withIssuedAt(new Date())
+ .withExpiresAt(new Date(System.currentTimeMillis() + TOKEN_VALIDITY_IN_MILLIS))
+ .withJWTId(UUID.randomUUID()
+ .toString())
+ .withNotBefore(new Date(System.currentTimeMillis() + 1000L))
+ .sign(algorithm);
+
+ return jwtToken;
+ }
+
+ private static DecodedJWT verifyJWT(String jwtToken) {
+ try {
+ DecodedJWT decodedJWT = verifier.verify(jwtToken);
+ return decodedJWT;
+ } catch (JWTVerificationException e) {
+ System.out.println(e.getMessage());
+ }
+ return null;
+ }
+
+ private static boolean isJWTExpired(DecodedJWT decodedJWT) {
+ Date expiresAt = decodedJWT.getExpiresAt();
+ return expiresAt.getTime() < System.currentTimeMillis();
+ }
+
+ private static String getClaim(DecodedJWT decodedJWT, String claimName) {
+ Claim claim = decodedJWT.getClaim(claimName);
+ return claim != null ? claim.asString() : null;
+ }
+
+ public static void main(String args[]) throws InterruptedException {
+
+ initialize();
+
+ String jwtToken = createJWT();
+ System.out.println("Created JWT : " + jwtToken);
+
+ DecodedJWT decodedJWT = verifyJWT(jwtToken);
+ if (decodedJWT == null) {
+ System.out.println("JWT Verification Failed");
+ }
+
+ Thread.sleep(1000L);
+
+ decodedJWT = verifyJWT(jwtToken);
+ if (decodedJWT != null) {
+ System.out.println("Token Issued At : " + decodedJWT.getIssuedAt());
+ System.out.println("Token Expires At : " + decodedJWT.getExpiresAt());
+ System.out.println("Subject : " + decodedJWT.getSubject());
+ System.out.println("Data : " + getClaim(decodedJWT, DATA_CLAIM));
+ System.out.println("Header : " + decodedJWT.getHeader());
+ System.out.println("Payload : " + decodedJWT.getPayload());
+ System.out.println("Signature : " + decodedJWT.getSignature());
+ System.out.println("Algorithm : " + decodedJWT.getAlgorithm());
+ System.out.println("JWT Id : " + decodedJWT.getId());
+
+ Boolean isExpired = isJWTExpired(decodedJWT);
+ System.out.println("Is Expired : " + isExpired);
+ }
+ }
+
+}
diff --git a/security-modules/jwt/src/test/java/com/baeldung/jwt/auth0/Auth0JsonWebTokenUnitTest.java b/security-modules/jwt/src/test/java/com/baeldung/jwt/auth0/Auth0JsonWebTokenUnitTest.java
new file mode 100644
index 0000000000..a9c3b4185d
--- /dev/null
+++ b/security-modules/jwt/src/test/java/com/baeldung/jwt/auth0/Auth0JsonWebTokenUnitTest.java
@@ -0,0 +1,127 @@
+package com.baeldung.jwt.auth0;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.Date;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTVerifier;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.IncorrectClaimException;
+import com.auth0.jwt.exceptions.SignatureVerificationException;
+import com.auth0.jwt.exceptions.TokenExpiredException;
+import com.auth0.jwt.interfaces.Claim;
+import com.auth0.jwt.interfaces.DecodedJWT;
+
+public class Auth0JsonWebTokenUnitTest {
+
+ private static final String SECRET = "baeldung";
+ private static final String SECRET_NEW = "baeldung.com";
+ private static final String ISSUER = "Baeldung";
+ private static final String DATA_CLAIM = "userId";
+ private static final String DATA = "1234";
+
+ private static Algorithm algorithm;
+ private static Algorithm algorithmWithDifferentSecret;
+ private static JWTVerifier verifier;
+ private static String jwtToken;
+
+ @BeforeAll
+ public static void setUp() {
+ algorithm = Algorithm.HMAC256(SECRET);
+
+ algorithmWithDifferentSecret = Algorithm.HMAC256(SECRET_NEW);
+
+ verifier = JWT.require(algorithm)
+ .withIssuer(ISSUER)
+ .build();
+ }
+
+ private static boolean isJWTExpired(DecodedJWT decodedJWT) {
+ Date expiresAt = decodedJWT.getExpiresAt();
+ return expiresAt.getTime() < System.currentTimeMillis();
+ }
+
+ private static DecodedJWT verifyJWT(String jwtToken) {
+ DecodedJWT decodedJWT = verifier.verify(jwtToken);
+ return decodedJWT;
+ }
+
+ @Test
+ public void givenJWT_whenNotExpired_thenCheckingIfNotExpired() {
+
+ jwtToken = JWT.create()
+ .withIssuer(ISSUER)
+ .withClaim(DATA_CLAIM, DATA)
+ .withExpiresAt(new Date(System.currentTimeMillis() + 1000L))
+ .sign(algorithm);
+
+ DecodedJWT decodedJWT = verifyJWT(jwtToken);
+ assertNotNull(decodedJWT);
+ assertFalse(isJWTExpired(decodedJWT));
+ }
+
+ @Test
+ public void givenJWT_whenExpired_thenCheckingIfExpired() {
+
+ jwtToken = JWT.create()
+ .withIssuer(ISSUER)
+ .withClaim(DATA_CLAIM, DATA)
+ .withExpiresAt(new Date(System.currentTimeMillis() - 1000L))
+ .sign(algorithm);
+
+ assertThrows(TokenExpiredException.class, () -> {
+ verifyJWT(jwtToken);
+ });
+ }
+
+ @Test
+ public void givenJWT_whenCreatedWithCustomClaim_thenCheckingForCustomClaim() {
+
+ jwtToken = JWT.create()
+ .withIssuer(ISSUER)
+ .withClaim(DATA_CLAIM, DATA)
+ .withExpiresAt(new Date(System.currentTimeMillis() + 1000L))
+ .sign(algorithm);
+
+ DecodedJWT decodedJWT = verifyJWT(jwtToken);
+ assertNotNull(decodedJWT);
+
+ Claim claim = decodedJWT.getClaim(DATA_CLAIM);
+ assertEquals(DATA, claim.asString());
+ }
+
+ @Test
+ public void givenJWT_whenCreatedWithNotBefore_thenThrowException() {
+
+ jwtToken = JWT.create()
+ .withIssuer(ISSUER)
+ .withClaim(DATA_CLAIM, DATA)
+ .withNotBefore(new Date(System.currentTimeMillis() + 1000L))
+ .sign(algorithm);
+
+ assertThrows(IncorrectClaimException.class, () -> {
+ verifyJWT(jwtToken);
+ });
+ }
+
+ @Test
+ public void givenJWT_whenVerifyingUsingDifferentSecret_thenThrowException() {
+
+ jwtToken = JWT.create()
+ .withIssuer(ISSUER)
+ .withClaim(DATA_CLAIM, DATA)
+ .withExpiresAt(new Date(System.currentTimeMillis() + 1000L))
+ .sign(algorithmWithDifferentSecret);
+
+ assertThrows(SignatureVerificationException.class, () -> {
+ verifyJWT(jwtToken);
+ });
+ }
+}
diff --git a/security-modules/pom.xml b/security-modules/pom.xml
index 480ee0819e..1ed081a273 100644
--- a/security-modules/pom.xml
+++ b/security-modules/pom.xml
@@ -20,8 +20,9 @@
jee-7-security
jjwt
+ jwt
oauth2-framework-impl
- sql-injection-samples
+ sql-injection-samples
\ No newline at end of file