3

In general what is the best way to authenticate the access token in interceptors, If the access token information is stored in HashMap for each and every user, the hashmap grows as the number of users increases. If we query database for every api request, it increases load on database. Please mention if there are any other techniques you know. And also what other things I need to consider while authenticating the access token for every request. What are the pre-processing and post-processing steps while authenticating access token.

Thanks in Advance.

Mohasin Ali
  • 3,955
  • 1
  • 20
  • 24

3 Answers3

3

Check out Json Web tokens. Using them allows your server to become stateless (not saving any sessions on memory). Its concept is to pass a digital signed token, for every request, and checking that the signature is correct for integrity. Json Web Encryption also can encrypt sensitive data along the token (such as user id).

This makes it very easy to work on a distributed environment

Check out this website: https://jwt.io/. There are some implementations in java and plenty of code examples to start with.

aviad
  • 1,553
  • 12
  • 15
2

Some words about authentication with tokens

Once you are using JAX-RS, have a look at this answer that I wrote a while ago.

Your tokens can be any randon string persisted to some storage. On the other hand, JWT tokens allow you to have stateless authentication (no persistence). If you need to track the JWT tokens (to revoke them, for example), you must persist at least their identifier (the jti claim). A HashMap shouldn't be used to "persist" tokens (that's not a real persistence and it won't scale). Instead, consider a database like Redis.

To generate and parse JWT tokens, have a look this library created by Stormpath and maintained by a community of contributors. I currently use it in some applications and I can say with confidence that it works just fine and it's easy to use.

Keep reading for more details about the authentication process.

Authentication with tokens at a glance

In a few words, a token-based authentication follow these steps:

  1. The client sends their credentials (username and password) to the server.
  2. The server authenticates the credentials and generates a token.
  3. The server stores the previously generated token in some storage along with the user identifier and an expiration date.
  4. The server sends the generated token to the client.
  5. In every request, the client sends the token to the server.
  6. The server, in each request, extracts the token from the incoming request. With the token, the server looks up the user details to perform authentication and authorization.
    1. If the token is valid, the server accepts the request.
    2. If the token is invalid, the server refuses the request.
  7. The server can provide an endpoint to refresh tokens.

Using JAX-RS to implement authentication based on tokens

The authentication starts when the server receives the hard credentials (username and password) of a user and exchanges them with a token that the client must send in each request:

@Path("/authentication")
public class AuthenticationResource {

    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public Response authenticateUser(Credentials credentials) {
    
        try {

            // Authenticate the user using the credentials provided
            String username = credentials.getUsername();
            String password = credentials.getPassword();
            authenticate(username, password);

            // Issue a token for the user
            String token = issueToken(username);

            // Return the token on the response
            return Response.ok(token).build();

        } catch (Exception e) {
            return Response.status(Response.Status.UNAUTHORIZED).build();
        }      
    }

    private void authenticate(String username, String password) throws Exception {
        // Authenticate against a database, LDAP, file or whatever
        // Throw an Exception if the credentials are invalid
    }

    private String issueToken(String username) {
        // Issue a token (can be a random String persisted to a database or a JWT token)
        // The issued token must be associated to a user
        // Return the issued token
    }
}

A filter will be used to extract the token from the HTTP request and validate it:

@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {

        // Get the HTTP Authorization header from the request
        String authorizationHeader = 
            requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);

        // Check if the HTTP Authorization header is present and formatted correctly 
        if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
            throw new NotAuthorizedException("Authorization header must be provided");
        }

        // Extract the token from the HTTP Authorization header
        String token = authorizationHeader.substring("Bearer".length()).trim();

        try {

            // Validate the token
            validateToken(token);

        } catch (Exception e) {
            requestContext.abortWith(
                Response.status(Response.Status.UNAUTHORIZED).build());
        }
    }

    private void validateToken(String token) throws Exception {
        // Check if it was issued by the server and if it's not expired
        // Throw an Exception if the token is invalid
    }
}

For further details, have a look at this answer.

JSON Web Token

JSON Web Token (JWT) is defined by the RFC 7519 and I think it fits really well for your needs.

It's a standard method for representing claims securely between two parties (in this situation, client and server). JWT is a self-contained token and enables you to store a user identifier, an expiration date and whatever you want (but don't store passwords) in a payload, which is a JSON encoded as Base64.

The payload can be read by the client and the integrity of the token can be easily checked by verifying its signature on the server.

To find some great resources to work with JWT, have a look at http://jwt.io.

And remember: when sending sensitive data over the wire, your best friend is HTTPS. It protects your application against the man-in-the-middle attack.

Tracking the tokens

You won't need to persist JWT tokens if you don't need to track them.

Althought, by persisting the tokens, you will have the possibility of invalidating and revoking the access of them. To keep the track of JWT tokens, instead of persisting the whole token, you could persist the token identifier (the jti claim) and some metadata (the user you issued the token for, the expiration date, etc) if you need.

There are many databases where you can persist your tokens. Depending on your requirements, you can explore different solutions such as relational databases, key-value stores or document stores.

Your application can provide some functionality to revoke the tokens, but always consider revoking the tokens when the users change their password. When persisting tokens, always consider removing the old ones in order to prevent your database from growing indefinitely.

Community
  • 1
  • 1
cassiomolin
  • 124,154
  • 35
  • 280
  • 359
1

You can combine both HashMap and database. In your case, HashMap can be used as a cache. The first time user was authenticated, access token information of this user should store to HashMap. The next APIs, we will check if the access token is exist in HashMap. If it exists, we use it to authenticate, if not we will query from database and store it to HashMap. You need to expire access tokens in HashMap that was not used for a duration.

Lucas Pham
  • 26
  • 4