Best practices for managing auth token

23,922

Solution 1

For brevity I'll assuming you're calling an endpoint that you can't change. How you should implement will heavily depend on whether the token is app or user based (one token for all users on a shared app instance or one token per user).

If it's one auth token for the entire app:

  • Store it in memory along with a time-to-live timestamp (or alternatively catch the token expired error, request a new token and retry the original request), refresh it if it doesn't exist/is expired
  • If you're concerned about re-requesting API tokens after an application restart also store it in the database and load it at startup if it exists

If it's one token per user:

  • Store it in your user session, it's exactly what sessions are used for, if you're authing users then they'll have a session and the overhead is already there
  • If you don't want to re-request a token everytime they login store their current token in the DB and and load it into their session when they login

Solution 2

I'm assuming you are using OAuth for authorization. Whether you are using JWT or other tokens is irrelevant to this situation.

When performing authorization you will be issued an access_token with an expiration and, depending on the grant type you are requesting (Client credentials, Authorization code, Implicit, Resource owner), a refresh_token.

The client should keep the access_token and the expiration. The refresh_token, if issued, must be kept secret (beware of using the correct grant for your use case).

In subsequent calls, your client should not request new tokens on each call, it should use the stored access_token.

Once the API starts returning 401 Unauthorized, the access_token has probably expired. Your client should try to refresh the access_token using the refresh_token if you got one.

If you have no refresh_token or the refresh request also failed, because the refresh_token is no longer valid, you can perform a new authorization flow.

You can use the expiration time as a clue to know when to get a new access_token either through refresh or through a new full authorization flow. This will avoid the 401 Unauthorized. In any case, your client should have a fall back policy when this response is received after having used a valid access_token for some calls.

Solution 3

You can create a manager and store the auth-cookie during login in thread local like the code below. You can get the cookie from getAuth() as long as the thread lives.

public class Manager {
    private static final ThreadLocal<String> SECURITY_CONTEXT = new ThreadLocal<>();

    public static void setAuth(String auth) {
        SECURITY_CONTEXT.set(auth);
    }

    public static String getAuth() {
        return SECURITY_CONTEXT.get();
    }

    public static void clear(){
        SECURITY_CONTEXT.remove();
    }
}

Solution 4

If you are worried about too many hits to the database, then i'm assuming there is a lot of web activity.

I would not recommend using Session in your case, but rather store the token in a cookie on the client.

In a high traffic environment(which i'm assuming yours is), the use of Session can consume a lot of server memory, and scalability can be a concern as well, having to keep sessions in sync within a cluster.

As @Cássio Mazzochi Molin also mentioned, you can use an in-memory cache to store any user specific data and tokens. This will reduce the hits to the database, and also allow you to scale the application easier, when the need arises.

Solution 5

I suggest you to use the following scenario:

1) First, call auth(username, password) rest api to get the auth token. If the given credentials are okay then just send back the auth cookie to the client with HTTP 200 response code.

2) Then, you can call protected rest apis. You need to send auth cookie with your request each time.

3) Servlet filter (or something similar) checks each incoming request and validates the token. If the token is valid then the request goes forward to the rest method, if not you need to generate an http 401/403 response.

I suggest you not to write your own authentication layer. Instead of install and use an existing one. I suggest you OpenAM. It is a superb open source access management system.

I also suggest you not to open session on the server side for authentication purpose. If you have 10 clients then 10 sessions needs to be managed by server. It is not a big issue. But if you have 100 or 1000 or millions different clients than you need more memory to store sessions on the server.

Share:
23,922
user_mda
Author by

user_mda

Updated on July 09, 2022

Comments

  • user_mda
    user_mda almost 2 years

    I am writing a REST client in Java using the HttpCLient , the REST API that I access needs an auth token for every REST action. This token is valid for 24 hours.

    The way I am handling this now is calling a "getAuth()" method everytime I need to make a REST call which seems like an overhead on the auth server.

    How can I conveniently store this auth token and manage its life cycle? Are there any documented best practices?

    I thought of the following solution

    public class MySession {
        String user;
        String pass;
        public MySession(String user, String pass) {
            this.user = user;
            this.pass = pass;
        }
    
        public getAuth() {
            //user user, pass to get auth token 
        }
    }
    

    and then pass the sessions object to any class that nees the token. If the token is expired, just call this method again