2

I'm developing Backend Service using JAX-RS and JWT for authentication. But with JWT, when user login on new devices, new JWT token will be generated and previous JWT token for this user will be invalid. So how can I use session or something like that to remember login of user on all devices which they have ?

Here is my code for login and check authentication :

    @POST
    @Path("/authenticate")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response authenticateCredentials(@HeaderParam("email") String email,
            @HeaderParam("password") String password, @HeaderParam("accessToken") String accessToken,
            @HeaderParam("type") String loginType)
            throws JsonGenerationException, JsonMappingException, IOException {

        logger.info("Authenticating User Credentials...loginType : " + loginType);

        StatusMessage<Users> statusMessage = null;
        String jweSerialization = null;

        if(loginType == null){
            statusMessage = new StatusMessage();
            statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
            statusMessage.setMessage("login type value is missing...");
            return Response.status(Status.PRECONDITION_FAILED.getStatusCode()).entity(statusMessage).build();
        }

        LoginType type = LoginType.valueOf(loginType);

        switch (type) {
        case systems:
            if(email == null){
                statusMessage = new StatusMessage();
                statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
                statusMessage.setMessage("email value is missing...");
                return Response.status(Status.PRECONDITION_FAILED.getStatusCode()).entity(statusMessage).build();
            }

            if(password == null){
                statusMessage = new StatusMessage();
                statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
                statusMessage.setMessage("password value is missing...");
                return Response.status(Status.PRECONDITION_FAILED.getStatusCode()).entity(statusMessage).build();
            }

            Users user = usersDAO.validate(email, password);
            logger.info("user after validate : " + user);
            if(user == null){
                statusMessage = new StatusMessage();
                statusMessage.setStatus(Status.NOT_FOUND.getStatusCode());
                statusMessage.setMessage("User not found...");
                return Response.status(Status.NOT_FOUND.getStatusCode()).entity(statusMessage).build();
            }
            jweSerialization = getJWEToken(user);
            user.setPassword(null); //not return password and OTP
            user.setOTP(null);
            statusMessage = new StatusMessage<Users>();
            statusMessage.setStatus(Status.OK.getStatusCode());
            statusMessage.setMessage(jweSerialization);
            statusMessage.setData(user);
            logger.info("statusMessage : " + statusMessage);

            return Response.status(Status.OK.getStatusCode()).entity(statusMessage).build();

        case facebook:
            if(email == null){
                statusMessage = new StatusMessage<Users>();
                statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
                statusMessage.setMessage("email value is missing...");
                return Response.status(Status.PRECONDITION_FAILED.getStatusCode()).entity(statusMessage).build();
            }
            if(accessToken == null){
                statusMessage = new StatusMessage<Users>();
                statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
                statusMessage.setMessage("facebook access token value is missing...");
                return Response.status(Status.PRECONDITION_FAILED.getStatusCode()).entity(statusMessage).build();
            }


            FacebookAuth facebookAuth = new FacebookAuth();
            SocialUser fbUser = facebookAuth.verifySocialUser(accessToken);
            if(fbUser == null){
                statusMessage = new StatusMessage<Users>();
                statusMessage.setStatus(Status.FORBIDDEN.getStatusCode());
                statusMessage.setMessage("Fail while verify facebook user...");
                return Response.status(Status.FORBIDDEN.getStatusCode()).entity(statusMessage).build();
            }

            Users fb_user = usersDAO.validate(fbUser.getEmail(), null);
            if(fb_user == null){
                statusMessage = new StatusMessage<Users>();
                statusMessage.setStatus(Status.NOT_FOUND.getStatusCode());
                statusMessage.setMessage("User not found...");
                return Response.status(Status.NOT_FOUND.getStatusCode()).entity(statusMessage).build();
            }

            jweSerialization = getJWEToken(fb_user);
            fb_user.setPassword(null); //not return password and OTP
            fb_user.setOTP(null);
            statusMessage = new StatusMessage<Users>();
            statusMessage.setStatus(Status.OK.getStatusCode());
            statusMessage.setMessage(jweSerialization);
            statusMessage.setData(fb_user);
            logger.info("statusMessage : " + statusMessage);

            return Response.status(Status.OK.getStatusCode()).entity(statusMessage).build();
        case google:
            if(email == null){
                statusMessage = new StatusMessage<Users>();
                statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
                statusMessage.setMessage("email value is missing...");
                return Response.status(Status.PRECONDITION_FAILED.getStatusCode()).entity(statusMessage).build();
            }
            if(accessToken == null){
                statusMessage = new StatusMessage<Users>();
                statusMessage.setStatus(Status.PRECONDITION_FAILED.getStatusCode());
                statusMessage.setMessage("google access token value is missing...");
                return Response.status(Status.PRECONDITION_FAILED.getStatusCode()).entity(statusMessage).build();
            }

            GoogleAuth googleAuth = new GoogleAuth();
            SocialUser ggUser = googleAuth.verifySocialUser(accessToken);
            if(ggUser == null){
                statusMessage = new StatusMessage<Users>();
                statusMessage.setStatus(Status.FORBIDDEN.getStatusCode());
                statusMessage.setMessage("Fail while verify Goolge user...");
                return Response.status(Status.FORBIDDEN.getStatusCode()).entity(statusMessage).build();
            }

            Users gg_User = usersDAO.validate(ggUser.getEmail(), null);
            if(gg_User == null){
                statusMessage = new StatusMessage<Users>();
                statusMessage.setStatus(Status.NOT_FOUND.getStatusCode());
                statusMessage.setMessage("User not found...");
                return Response.status(Status.NOT_FOUND.getStatusCode()).entity(statusMessage).build();
            }

            jweSerialization = getJWEToken(gg_User);
            gg_User.setPassword(null); //not return password and OTP
            gg_User.setOTP(null);
            statusMessage = new StatusMessage<Users>();
            statusMessage.setStatus(Status.OK.getStatusCode());
            statusMessage.setMessage(jweSerialization);
            statusMessage.setData(gg_User);
            logger.info("statusMessage : " + statusMessage);

            return Response.status(Status.OK.getStatusCode()).entity(statusMessage).build();

        default:
            statusMessage = new StatusMessage<Users>();
            statusMessage.setStatus(Status.FORBIDDEN.getStatusCode());
            statusMessage.setMessage("Wrong login type...");
            return Response.status(Status.FORBIDDEN.getStatusCode()).entity(statusMessage).build();
        }
    }
AcidBurn
  • 73
  • 2
  • 15

1 Answers1

1

You can access resources in JAX-RS just like a servlet since JAX-RS is actually built on top of servlets. So yes, you can access Session and store your client specific information in sessions to maintain states (Here is an example).

However, this is strictly discouraged to maintain states in session in web services like we do in client/server settings. HTTP is a stateless protocol, so servers are supposed to serve each request in isolation. The cost of maintaining states for each of the clients grows with the number of clients and has the potential to exhaust your server resources. We tradeoff this cost in client/server mode to give a better user experience. For example, a server can cache frequently accessed data (based on previous request patterns) in a session so that the response time is decreased over-time by keeping the communication overhead as minimal as possible. In contrast, in web services servers actually serves other servers. So in this scenario, the tradeoff is not as rewarding as the actual client/server setting. Because for a server to server communication bandwidth is not a problem. A server (acting as a client) can provide any necessary details while requesting a resource to the other server.

Yours is a legitimate case to use Session. Since you are actually communicating with clients using JAX-RS and need to maintain states (at least for authentication purpose). Following is a set of recommendation that you can follow.

After login with the username and password, you can provide the authentication token to the user and store the user information with the token. For each subsequent request, the client can send the token to the server so that the server can look up the user identity. In the following thread, you can see the defacto protocol in much more details.

You can consider using any off-the-shelf caching mechanism (e.g., JCS, Ehcache, Redis, Memcached, etc.) to store your sessions so that you can take the full advantage of load balancing your server instances. If you are using JBoss application server, Infinispan is already available to you. If you are using Weblogic server, you can use Oracle Coherence that comes with it. Just choose one that suits best for you.

Sazzadur Rahaman
  • 6,938
  • 1
  • 30
  • 52
  • 1
    Many thanks for reply, Sazzadur. Your information very very useful for me. I will research follow your guide to find the solution which suits with me. Thanks – AcidBurn Jul 17 '18 at 04:57