User session management in microservices and APIs

Jeevan Patil
Deskera Engineering
4 min readMay 4, 2020

--

Remember the good old days when the entire application code used to be in a single repository. The UI code, and backend code used to be packaged into one file and deployed on the server. If we consider Java-based web applications, they were mostly deployed on tomcat containers or enterprise containers like JBoss. The user session used to be managed on the server side itself. In older spring applications, the user details were stored in a security context object. Wherever one needed to know which user requests the server is handling, we could just grab the username and roles from a security context. This is not followed anymore because of the reasons discussed in this article.

With the advent of single-page applications, mobile applications, docker, and microservices, the way we handle user session management is changed. APIs are written and deployed independently of UI code, be it web or mobile. The APIs are stateless meaning they do not persist or know any information about who invoked the API. The session is created only for that particular HTTP request.

Why we need user information — We did similar stuff while developing the Deskera Books application. Consider you are working on a SAAS platform. Multiple organizations sign up and start using the application. Every organization trusts that the information will not be shared or leaked with any other organization. We as developers need to make sure that the organization's information is secure. For this to happen, we need to understand which user or organization the HTTP request belongs to. The API will only deal with the data which belongs to that user and the organization.

How should we handle the user session information — Suppose you have multiple micro-services dockerized and deployed. The application generates a JWT token after the user logs into the application and the web UI (or mobile app for that matter) code keeps this token in local storage to be passed along the subsequent HTTP requests. Generally, spring applications code follows layered architecture. It has a controller, service, and repository layer. To know more about these layers, you can go through the answer here.

Now, there should be a way to get this token in any of these layers. We need the user id or organization id from the token to be passed to the SQL query. This information is critical in order to keep the data segregated from each other and to secure the data.

How can we achieve this?

We are going to make use of interceptors for this. I am going to explain the way to do this in Spring Boot and am very sure that other frameworks too have a concept of interceptors.

Controllers in spring boot handle the HTTP requests. Each controller method is mapped to an HTTP request. When an API is invoked, these controller methods are executed. What we have to do is to write a class that will intercept the request before being passed onto the controller method. This interceptor class will extract the token from the HTTP request header or cookie and process it.

We also need to create a bean of request scope of type UserSession. This means Whatever you set into the UserSession object will be valid for one HTTP request. The next request will set those details again.

@Bean
@Primary
@Scope(WebApplicationContext.SCOPE_REQUEST)
public UserSession provideUserInfo() {
// here we return an empty object which is then populated by the interceptor
return new UserSession();
}

This is what the interceptor would look like.

@Component
@Log4j2
public class AuthenticationInterceptor extends HandlerInterceptorAdapter {
// this will provide us the user session bean from the spring context
@Autowired
private Provider<UserSession> userInfoProvider;
@Override
public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) {
final UserSession user = userInfoProvider.get();
final String token = request.getHeader(“header_name_which_carries_the_token”);
try {
// this method internally decodes the token and sets the attributes in UserSession object
user.setUserSession(token);
} catch (final Exception e) {
// invalid token exceptions
}
return true;
}
}

This interceptor will intercept all the requests and check whether the token is valid. If the token is valid, it will be decoded and an UserSession object will be populated from the token attributes.

Suppose the following is the UserSession object which holds token information.

@Data
public class UserSession {
private Long userId;
private Long orgId;
}

If the token is valid, not expired, and not tampered with, the UserSession object will be populated. You must have observed the Provider pattern in the interceptor class which is configured to provide a UserSession object from the spring context.

Now you can use this information anywhere in your service or controller classes.

@Service
public class UserServiceImpl implements UserService {
@Autowired
private Provider<UserSession> userSessionProvider;
public void add(final User user) {
// this is how you get hold of the user session
final UserSession userSession = userSessionProvider.get();
……
}
}

Conclusion:

1] With the interceptor approach you can verify the token. You can check if the token is valid, not expired, and not tampered with.

2] Interceptor would be the only place where you deal with the token. This logic is not scattered across the codebase. If tomorrow something related to token changes, this will be the only place where changes would occur.

3] With this approach, the other services do not have to worry about how the token is created and managed.

--

--