Jwt Authentication Java

Build authentication into your Java API’s with Json Web Token (Jwt)

In this article, I walk you through the development of a very basic Java JAX_RS web-services with Jwt (Json web token) authentication. For web-services, we’re going to use Jersey which is an open source framework for RESTful Web Services in Java. Before jump into coding and start authenticating the user I want to tell you a brief workflow of our application.

Application Workflow

  • In order to use the web-services, the user sends a request to get a token by passing his/her credentials.
  • Our web-service validates the credentials, and return an encrypted privateKey aka token, which will only be valid for the next thirty minutes.
  • With every request, the user needs to send the privateKey in the request header, and if the key is invalid or expires then we send back the WebApplicationException, else we simply return the result.

We’ll implement a custom ContainerRequestFilter, which is in the simple words, a gateway of our application. Every request made by the client first came to our custom filter and we validate the privateKey before allowing the request to go to any service.

Like I said at the start of this article, we’ll create a privateKey aka token with Jwt (Json web token). In order to create a web-based token, we’ll use the Java Jwt library made by mighty lhazlewood.

There’s a great article on Json Web Token go and check it out => 5 Easy Septs to understand Json Web Token (Jwts)

Application Workflow Diagram

As mention above, in the Application Workflow section our server or web-services will generate a privateKey or Jwt token for the user. With the Jwt token, the user then safely communicate with the application. Below is the workflow diagram.

Jwt workflow diagram

This is indeed a simplistic introduction to our application.  Next, below is the demo of our application for visualization.

In case I miss something, you can follow me by looking in the code which I pushed on GitHub.

Get Started

To begin, create a new Maven web project using an IDE and open the pom.xml file. Here we need to add dependencies for Jersey and Jwt.

<dependencies>
        ...........
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-core</artifactId>
            <version>1.19.4</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-grizzly2</artifactId>
            <version>1.19.4</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-json</artifactId>
            <version>1.19.4</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.ext</groupId>
            <artifactId>jersey-entity-filtering</artifactId>
            <version>2.14</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.10.5</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.10.5</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.10.5</version>
            <scope>runtime</scope>
        </dependency>
        .........
    </dependencies>

Once you’ve added the above dependencies compile the Maven project and you’re good to go.

In order to start building our application first let’s see our EndPoint class. Below is our HomeApiService, which is an EndPoint of our application.

@Path("/")
public class HomeApiService {

    @POST
    @Path(value = "authorization_service")
    @JwtCustomToken
    @Produces(MediaType.APPLICATION_JSON)
    public Response authorizationService(@QueryParam("username") String userName, @QueryParam("password") String password) {
        if (userName.isEmpty())
            return getResponse(new BaseResponse(BaseResponse.FAILURE, "username field cannot be empty!"));
        if (password.isEmpty())
            return getResponse(new BaseResponse(BaseResponse.FAILURE, "password field cannot be empty!"));
        String privateKey = JwTokenHelper.getInstance().generatePrivateKey(userName, password);
        return getResponse(new AuthorizationResponse(BaseResponse.SUCCESS, "You're authenticated successfully. Private key will be valid for 30 mins", privateKey));
    }
    
    @GET
    @Path("allDevices")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getAllDevices() {
         return getResponse(new DeviceCollection(Arrays.asList(new Device("Electric Kettle", 1, true), new Device("Computer", 1, true), new Device("Motorcycle", 3, false), new Device("Sandwich Maker", 4, true))));
    }

As you can see the basic JAX-RX Endpoint has two methods both returning a Response object. Now if you guy’s have seen the demo, then you probably see that in order to get allDevices we first need to authenticate our user and pass the privateKey inside the header of the request. Below is the explanation of the above two methods:

  • authorizationService: The user needs to get authenticated, invoking an HTTP POST and passing a username and password . Once authenticated, we simply call our jwTokenHelper class to create a token based on the username and password also set some other claims like thirty minutes expiration. You’ll see that how to create Jwt token in a couple of minutes.
  • getAllDevices: Simply returns a List of devices.

Filter checking for json web Token (Jwt)

So, we’ve added the EndPoint to our application but where did we check that the user adds the privateKey inside the header of the request. For this, we need to implement  ConatinerRequestFilter and after that the filter allows us to check the headers for every request. Like I said at the above of this article, the filter is like a gateway to our application. Every request sent by the client first came to our custom filter and after that, it goes to the EndPoint address. Below is JsTokenFilterNeeded class.

@Provider   
@JwtCustomToken   // 1
@Priority(Priorities.AUTHENTICATION)  // 2
public class JsTokenFilterNeeded implements ContainerRequestFilter {
   
   private static final String AUTHORIZATION_SERVICE_PATH = "authorization_service";  
   private static final String PRIVATE_KEY = "privateKey";   
   private JwTokenHelper jwTokenHelper = JwTokenHelper.getInstance();

   @Override
    public ContainerRequest filter(ContainerRequest request) {  // 3
        String path = request.getPath();                     
        if(path.equals(AUTHORIZATION_SERVICE_PATH))        // |       4
             return request;
        String privateKeyHeaderValue = request.getHeaderValue(PRIVATE_KEY);  // 5
        if (privateKeyHeaderValue == null || privateKeyHeaderValue.isEmpty())
            throw new WebApplicationException(getUnAuthorizeResponse(PRIVATE_KEY + " is missing in header"))   // 6
        try {
             provider.jwTokenHelper.claimKey(privateKeyHeaderValue);   // 7
        } catch(Exception e) {
            if (e instanceof ExpiredJwtException) {
                throw new WebApplicationException(getUnAuthorizeResponse(PRIVATE_KEY + " is expired"));
            } else if (e instanceof MalformedJwtException) {
                throw new WebApplicationException(getUnAuthorizeResponse(PRIVATE_KEY + " is not correct"));
            }
        }
        return request;
    }

    private Response getUnAuthorizeResponse(String message) {
       return Response.ok(BaseResponse.FAILURE, message
       ).status(Response.Status.UNAUTHORIZED)
        .type(MediaType.APPLICATION_JSON)
        .build()
    }
}

Let’s go through the logic behind the implementation.

  1. The JwtCustomToken is just a JAX-RS name binding (think of it’s as a CDI interceptor binding), so it’s just an annotation that binds to a filter. We’ll see that how to create JwtCustomToken annotation in a couple of minutes.
  2. Priority for user authentication. You can read more about other priorities in this link.
  3. The filter method is invoked at runtime whenever a new request came.
  4. If the path of the current request is authorization_service then we simply return the ContainerRequest immediately because at here our client trying to create a new privateKey. Also in here, we don’t need to check that user added the Jwt token inside the header request or not.
  5. Gets the HTTP Authorization header from the request (the privateKey).
  6. If privateKey is not added inside the header of the request then we simply throw WebApplicationException with a message (privateKey is missing in header).
  7. It validates the token (privateKey) using the Jwt library. If the token is valid then, in the end, we simply return the ContainerRequest and if it is not valid or token expires WebApplicationException thrown with a specific message.

The following shows the code snippet for JwtCustomToken annotation class.

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@NameBinding
public @interface JsonTokenNeeded {
}

Issue a json web token (Jwt) or privateKey

Now we have a filter that checks that the privateKey is passed inside the HTTP header. But how is this token issued? Here comes our JwTokenHelper class which create JJwt token based on user’s username and password also claims the token.

public class JwTokenHelper {

   private static JwTokenHelper jwTokenHelper = null;
   private static final long EXPIRATION_LIMIT = 30;
   private Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);

   private JwTokenHelper() {
   }

   public static JwTokenHelper getInstance() {
      if(jwTokenHelper == null)
           jwTokenHelper = new JwTokenHelper();
      return jwTokenHelper;
   }

   //  1
   public String generatePrivateKey(String username, String password) {
       return Jwts
                .builder()
                .setSubject(username)
                .setSubject(password)
                .setExpiration(getExpirationDate())
                .signWith(key)
                .compact();
   }
   
   // 2
   public void claimKey(String privateKey) throws ExpiredJwtException, MalformedJwtException  {
      Jwts
                .parser()
                .setSigningKey(key)
                .parseClaimsJws(privateKey);
   }

   // 3
   private Date getExpirationDate() {
       long currentTimeInMillis = System.currentTimeMillis();
       long expMilliSeconds = TimeUnit.MINUTES.toMillis(EXPIRATION_LIMIT);
       return new Date(currentTimeInMillis + expMilliSeconds);
   }

}

Below is the explanation of the above code.

  1. In here we set few claims for Json Web Token. Add the username and password, set expiration date for privateKey and sign in with SignatureAlgorithm.HS256.
  2. Validating the key with Jwts parser. If the key is not valid then the method throws MalformedJwtException and if it expires then it throws ExpiredJwtException.
  3. This is the method which sets that the privateKey is only valid for the next thirty minutes.

Now that we’ve all part’s, let’s put them together and run our application. In this article, we only see the configuration by extending ResourceConfig instead of a web.xml file.

public class MyResourceConfig extends DefaultResourceConfig {

    
    public MyResourceConfig() {
        super(HomeApiService.class); 
        Map<String, Object> maps = new HashMap<String, Object>();
        maps.put(ResourceConfig.PROPERTY_CONTAINER_RESPONSE_FILTERS, CORSFilter.class);  
        maps.put(ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS, JsTokenFilterNeeded.class);
        setPropertiesAndFeatures(maps);
    }
}

The DefaultResourceConfig class is itself an extension of JAX-RX Application class and also provides some convenience methods like setPropertiesAndFeatures to register our filters. Now in our MyResourceConfig constructor, we define a Map<String,Object> that will hold our resource and response filters and later set maps to ResourceConfig.

Run your rest Service

To run your web application paste the following code snippet inside your main method and afterward run the application like you run a simple java program.

public static void main(String[] args) {
        ResourceConfig resourceConfig = new MyResourceConfig();
        try {
             // change with your application ip and port address. 
            GrizzlyServerFactory.createHttpServer(URI.create("http://000.000.000.000:xxxx"), resourceConfig);   
            System.in.read();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Closing Up

In this article, I just wanted to show you how easy it is to issue and validate the Json Web Token with JAX-RX. Anything which I miss in this article please let me know via comment.

What’s next

Thank you for being here and keep reading…

Similar Posts

2 Comments

Comments are closed.