Search code examples
restapiauthenticationjersey

How to implement user login in Jersey API


I am implementing RESTful API using javax.ws.rs. The response of the calls that I need to implement requires knowing which user is logged in currently. I tried making a separate call for the user login:

api.myapi.co.uk/authenticate?username=xxxx&password=xxxx

where I basically save the user information is a global variable and then tried to make another call to retrieve information from the database based on the user that has been saved earlier but I find the value as null during the second call. What am I missing? Is my approach wrong? do you have any suggestions please?


Solution

  • Your code probably looks like this, right?

    @Path("/")
    public class MyResource{
      private String username;
      private String password;
      @Path("authenticate")
      public String authenticate(@QueryParam("username") username, @QueryParam("password") password) {
        if(!username.equals("zainab") || !password.equals("letmein"))
          return "Incorrect username or password";
        this.username=username;
        this.password=password;
        return "Sucessfully authenticated";
      }
      @Path("secret")
      public String secret() {
        if(username == null || password == null)
          return "Sorry, not authorized";
        return "You are authorized: "+username;
      }
    }
    

    If so, the problem is that JAX-RS creates a new Resource object for each request. A request to "/secret" then uses a new instance of MyResource, which has username and password as null.

    Then, you might think, I'll just make it static! Then, your resource can't handle concurrent requests. What if Person A calls "/authenticate", then "/secret". Then Person B calls "/secret" without authenticating. He can then access "/secret" without authenticating!

    Anyways, this violates the idea of RESTful services. The S in RESTful stands for "Stateless". This means that the server should store no state per client, and possibly give the user a token to pass with concurrent requests.

    One possibility is to accept the username and password for every request to secret ("/secret?username=zainab&password=letmein"). Or you could implement token-based authentication, where the user calls "/authenticate" to get a token, and they pass that token on all later requests. Here is a link to help with that.

    Also, note that username and password is usually not send in the URL as a query param, but instead in the Authorization HTTP header as such Authorization: base64encode("USERNAME:PASSWORD")