Stateless Spring Security Part 2: Stateless Authentication

This second part of the Stateless Spring Security series is about exploring means of authentication in a stateless way. If you missed the first part about CSRF you can find it here.

So when talking about Authentication, its all about having the client identify itself to the server in a verifiable manner. Typically this start with the server providing the client with a challenge, like a request to fill in a username / password. Today I want to focus on what happens after passing such initial (manual) challenge and how to deal with automatic re-authentication of futher HTTP requests.

Common approaches

Session Cookie based

The most common approach we probably all know is to use a server generated secret token (Session key) in the form of a JSESSIONID cookie. Initial setup for this is near nothing these days perhaps making you forget you have a choice to make here in the first place. Even without further using this “Session key” to store any other state “in the session”, the key itself is in fact state as well.  I.e. without a shared and persistent storage of these keys, no successful authentication will survive a server reboot or requests being load balanced to another server.

OAuth2 / API keys

Whenever talking about REST APIs and Security; OAuth2 and other types of API keys are mentioned. Basically they involve sending custom tokens/keys within the HTTP Authorization header. When used properly both relieve clients from dealing with Cookies using the header instead. This solves CSRF vulnerabilities and other Cookie related issues. One thing they do not solve however is the need for the server to check the presented authentication keys, pretty much demanding some persistent and maintainable shared storage for linking the keys to users/authorizations.

Stateless approaches

1. HTTP Basic Auth

The oldest and most crude way of dealing with authentication. Simply have the user send its username/password with every request. This probably sounds horrible, but considering any of the approaches mentioned above also send secret keys over the wire, this isn’t really all that less secure at all. Its mainly the user experience and flexibility that makes the other approaches a better choice.

2. Server signed tokens

A neat little trick to dealing with state across requests in a stateless way is to have the server “sign” it. It can then be transported back and forth between the client/server each request with the guarantee that it is not tampered with. This way any user identification data can be shared in plain-text, adding a special signing hash to it. Considering it is signed, the server can simply validate if the signing hash still matches the received content, without needing to hold any server-side state.

The common standard that can be used for this is JSON Web Tokens (JWT) which is still in draft. For this blog post I’d like to get down and dirty though, skipping full compliance and the scream for using a library that comes with it. Picking just what we actually need from it. (Leaving out the header/variable hash algoritms and url-safe base64 encoding)


Implementation

As mentioned we’re going to roll our own implementation, using Spring Security and Spring Boot to plug it all together. Without any library or fancy API obfuscating what’s really happening on the token level. The token is going to look like this in pseudo-code:

The dot in the token serves as a separator, so each part can be identified and decoded separately as the dot character is not part of any base64 encoded string. The HMAC stands for a Hash-based Message Authentication Code, which is basically a hash made from any data using a predefined secret key.

In actual Java the generation of the token looks a lot like the pseudo-code:

The relevant User properties used in the JSON are id, username, expires and roles, but could be anything you want really. I marked the “password” property of the User object to be ignored during jackson JSON serialization so it does not become part of the token:

For real worlds scenarios you probably just want to use a dedicated object for this.

The decoding of the token is a bit more complex with some input validation to prevent/catch parsing errors due to tampering with the token:

It essentially validates if the provided hash is the same as a fresh computed hash of the content. Because the createHmac method uses an undisclosed secret key internally to compute the hash, no client will be able to tamper with the content and provide a hash that is the same as the one the server will produce. Only after passing this test the provided data will be interpreted as JSON representing a User object.

Zooming in on the Hmac part, lets see the exact Java involved. First it must be initialized with a secret key, which I do as part of TokenHandler’s constructor:

After initialization it can be (re-)used, using a single method call! (doFinal’s JavaDoc reads “Processes the given array of bytes and finishes the MAC operation. A call to this method resets this Mac object to the state it was in when previously initialized via a call to init(Key) or init(Key, AlgorithmParameterSpec)…”)

I used some crude synchronization here, to prevent conflicts when used within a Spring Singleton Service. The actual method is very fast (~0.01ms) so it shouldn’t cause a problem unless your going for 10k+ requests per seconds per server.

Speaking of the Service, lets work our way up to a fully working token-based authentication service:

Pretty straight-forward, initializing a private TokenHandler to do the heavy lifting. It provides methods for adding and reading the custom HTTP token header. As you can see it does not use any (database driven) UserDetailsService to lookup the user details. All details required to let Spring Security handle further authorization checks are provided by means of the token.
Finally we can now plug-in all of this into Spring Security adding two custom filters in the Security configuration:

The StatelessLoginFilter adds the token upon successful authentication:

the StatelessAuthenticationFilter simply sets the authentication based upon the header:

Note that unlike most Spring Security related filters, I choose to continue down the filter chain regardless of successful authentication. I wanted to support triggering Spring’s  AnonymousAuthenticationFilter to support anonymous authentication. The big difference here being that the filter is not configured to map to any url specifically meant for authentication, so not providing the header isn’t really a fault.


 

Client-side Implementation

Client-side implementation is again pretty straight-forward. Again I’m keeping it minimalistic to prevent the authentication bit being lost in AngularJS details. If you’re looking for an AngularJS JWT example more thoroughly integrated with routes you should take a look here. I borrowed some of the interceptor logic from it.
Logging in, is simply a matter of storing the token (in localStorage):

Logging out is even simpler (no call to the server necessary):

To check if a user is “already logged in” ng-init=”init()” works nicely:

I choose to use an anonymously reachable endpoint to prevent triggering 401/403’s. You could also decode the token itself and check the expiration time, trusting the local client time to be accurate enough.

Finally in order to automate the process of adding the header a simple interceptor much like in last blog entry does nicely:

It also takes care of automatically clearing the token after receiving an HTTP 401 or 403, assuming the client isn’t going to allow calls to areas that need higher privileges.

TokenStorage

The TokenStorage is just a wrapper service over localStorage which I’ll not bother you with. Putting the token in the localStorage protects it from being read by script outside the origin of the script that saved it, just like cookies. However because the token is not an actual Cookie, no browser can be instructed add it to requests automatically. This is essential as it completely prevents any form of CSRF attacks. Thus saving you from having to implement any (Stateless) CSRF protection mentioned in my previous blog.


You can find a complete working example with some nice extras at github
Make sure you have gradle 2.0 installed and simply run it using “gradle build” followed by a “gradle run”. If you want to play with it in your IDE like Eclipse, go with “gradle eclipse” and just import and run it from within your IDE (no server needed).

 

 

38 thoughts on “Stateless Spring Security Part 2: Stateless Authentication

  1. Thank you so much ! I’ve been looking for such a tutorial for days !
    And your code is so clean that I had no problem to adapt it for my own application.

  2. Nice article. I hope it will be the one allowing me to make it with my JWT configuration.

    I see you are having a filter extend the AbstractAuthenticationProcessingFilter class. The Spring reference documentation is very short if existent at all on it. On the other hand it talks of the GenericFilterBean class which I extended to create my token authentication filter.

    I wonder if this same GenericFilterBean class could also be extended by the token creation filter. But maybe it’s not even a good idea ?

  3. I use a filter for first time password based login which extends the AbstractAuthenticationProcessingFilter (which extends from GenericFilterBean) and I use only to re-use its code where possible.

    The filter that handles the actual token based authentication actually already extends from GenericFilterBean

    • Hi, sorry for the late reply, been a bit busy lately.

      I’ve just checked the article and it seems to make a strong case against the usage of a very specific anti-pattern of dealing with encrypted cookies.

      The solution I described however uses HMAC which is a signing algoritm specifically designed to prevent the kind of tempering done in that blog. Furthermore its also described in the JWT standard.

      In general that author recommends the common database driven approach mostly to deal with the forcing a token/session to become invalid immediately. The tokens used in my blog post (JWT-tokens) auto-expire but on top of that you could always check on the fly if the user represented by the token is not locked/disabled if you must support an immediate deauthorization use-case.

      • Hi Robbert, thank you for the reply. Unfortunately I was not notified of it, so some months have past. I have actually cross-posted a mirror question in the above-mentioned blog post by Robert Winch (lead of Spring Security) with the link to your approach and he also shared his opinion. It would be interesting if you could maybe join the discussion there. I am sure that finding a common ground regarding this topic would be very beneficial to a large number of people.

      • PS: for the consistency – he points this approach as being vulnerable to replay attacks. However I might imagine that an argument could be made that if transport level security (SSL/TLS) is set up correctly, this problem is mitigated on a different level. What are your thought on this?

        • I’ve noticed your post and also Robert Winch vision on why being stateless should not be a goal by itself. Although I feel most reasons given are a bit far-fetched (like the replay attack); I do agree fully that being stateless is not a goal by itself.

          Furthermore I do not feel JWT should become the new enterprise default. I consider JWT to be more like a specialized tool on my belt for smaller use-cases like apps. Especially with recent efforts taken by the Spring Security to support high-performant API Gateway patterns.

  4. Thank you very much for this valuable article, I have been suffering trying to implement this with Spring Security, (I am not using gradle ).

    I am doing my best to learn as I am very new to Spring and server side development as well.

    May I ask you to kindly provide a security.xml equivalent to your security java configuration?

    I couldn’t achieve the XML configuration to work, as my current project doesn’t use a class to set up security, I need the security to be set with XML, a working sample would be very very helpful.

    Thank you very much in advance :)

    • As I use Spring Boot to deal with setting up the spring security basics, providing an equivalent XML variant is kind of cumbersome and incomplete as I do not know what your project does or does not included in its own security XML.

      Its probably best to start from this example:
      http://www.springbyexample.org/examples/simple-spring-security-webapp-spring-config.html
      and add the custom filters from this blog using the <security:custom-filter> element along with some additional beans to customize reading user/roles from database.

      • Thank you very much, I did it and your post is just the candle that helped me achieve this.

        Thanks for your reply and help :)

        • Hi, can you please share your xml file? I’m having issues trying to create a correct xml configuration

  5. Nice article! And thx for sharing the code.

    Based on your Security Config I think the Authentication object *is* stored in the http session as I believe that is Spring Security default behavior. This can be disabled using the HttpSecurity argument.
    Or didn’t you enabled this on purpose?
    If not it’s not completely stateless :-)

    Second question I have is related to the ng-init which checks if there is already a logged in user. Can you elaborate on this as I’m missing the need for this.

    • Inside my WebSecurityConfigurerAdapter I disable all defaults in its constructor by calling super(true). I believe this covers it.

      As for your second question, that ng-init method serves mostly for giving the client the proper initial state, either the user is “logged in” or any lingering token is removed from localStorage. It is not a mandatory step or anything.

      • Ah, I missed the constructor calling super(true).
        Thanks for explaining.

    • Indeed storing the token in localStorage is less secure than in a httpOnly cookie. There are a number of other considerations though why I choose for localStorage for my demo client:
      1. this way the client can access and show the data in the token
      2. Custom HTTP headers are easier for non-browser clients (IMHO one of the main use-cases for JWT)
      3. using a cookie means you’ll need additional CSRF protection (see my previous blog post if opting for this route)
      4. I consider protecting against XSS a lot easier than CSRF
      5. XSS cant steal httpOnly cookies, but it still can make the exact same API calls having the browser automatically use the cookie, so effectively httpOnly cookies are no real protection against XSS either.

      • Thanks for the clarification. I overlooked the 5th argument you provided. I thought that using an httpOnly cookie for the authentication token in combination with CSRF protection would be safer but I guess that an XSS exploit is still equally dangerous. The attacker might not be able to acquire the authentication token but that doesn’t prevent him from making “undesired” requests …

  6. Thanks for the tutorial, it’s very detail and easy to implement. I’ve tried Oauth2 before and it’s not very easy to setup and comprehend the whole thing. On top of it, it’s not easy to “scale out” as this “stateless” method – hence it’s named “stateless”!.

    I had some problems when configure this in a class that extends AbstractSecurityWebApplicationInitializer, I had to extend the AbstractAnnotationConfigDispatcherServletInitializer to get it working.

  7. Hi!

    Very nice article, many thanks! Just one remaining question: talking about serializing the User as a token, you said “for real worlds scenarios, you probably just want to use a dedicated object for this”, and that’s what I’m trying to do. What I ended with, is that the TokenAuthenticationService#getAuthentication() method needs to call the database to check whether a user with such an ID exists (the ID that was stored in my dedicated just-deserialized Token object).

    Could you validate this approach? Is there anyway to avoid querying the database another time?

    Thanks again,

    C.

    • The fact that you validate if the user still exists (or is locked/disabled) after receiving the token sounds like a good measure in itself. Its either that or simply assuming that given the token is not expired it is remains valid. Which might also be ok for certain types of clients.

      So for me it boils down to if you have a use-case for immediate removal/deactivation of users.

      To clarify about using a dedicated object: I meant mostly to use a POJO with exactly the properties you want for your token and not re-using the JPA entity User object, to avoid accidently exposing to much details in the token.

  8. That was a pleasant reading. Thank you!

    I’m a fan of keeping things stateless but till now I’ve never implemented security in a stateless manner. Things get promising with JWT but again I’m interested in features like letting the user see her active logins (and probably also record IPs) and having an option to immediately kill them all etc. So I always endup having a state.

    But I think I could go with a stateless approach and keep state only for immediate invalidations. Like having a revocation list for tokens that are still not expired but should not be valid.

  9. Pingback: Stateless Authentication with Spring Security and JWT | Technical Rex

  10. Well, i never leave comment but this time, i make an exception.
    Your article is really clean and i could adapt your code easily event with xml based configuration.

    Thank you very much.

  11. Hi Robbert van Waveren,

    Thank you so much for your example. As of now you are storing the tokens and users in HTTP session? Could you please explain more.
    And how can we get this with Databasae (like persisting users and authorization tokens)

    Thanks in advance.

    • User data is already stored in the database. The tokens are only stored in the browser, there is no HTTP Session in this scenario (else it would not be stateless).

  12. Thanks for the awesome tutorial. This is a great first step in getting JWT implemented! It would be great if you could do a follow up post that explores real world applications of JWT + REST including domain object access via stateless authorization.

    For example, your example only uses roles for authorization, but this is typically not enough in a REST architecture. /users/1 should not be able to modify /users/2 even if they are both role ‘USER’. Typical Spring implementations involve spring-security-acl which introduces a whole layer of complexity and state management. I was wondering if you had any suggestions for token embedded domain object authorization.

    • I haven’t actually came across this use-case within my own applications (other than the obvious “user” use-case example, which I usually cover with specific business logic within the controller).

      I hear what you’re saying though its indeed a good suggestion for a blog. Although I must say I’d probably prefer to separate authentication from authorization in such a way that an authorization implementation shouldn´t really be different, regardless of the authentication method.

  13. Hi Robbert,
    First of all thanks for such a nice and useful tutorial.

    I would like to know how should I implement create user api. As Right now I am getting “Access Denied” error if I try to implement create user controller.

    Thank you.

    • Make sure the authorization for your method/urls are in line with what you’re trying to accomplish.

      i.e. any /admin/… url requires you to be loged in as admin before using it. If you want anonymous users to create their own account, you should use a different url and explicitly give allow if for everyone in the security setup with permitAll.

      • Thanks Robot,
        I have implemented the create account api for anonymous users. Now the problem is how to authenticate user as they create acount, means how to auto-login them on calling create account api.

  14. Hey i want to know if i am using token authentication service on server side and want to use particular rest service on server side for that i have to send token with request right! So i want to know how to do this with Rest client(POSTMAN) without using angular.

  15. Hi Robbert

    can i implement this model to handle for large number of token creation because my application will be used by multiple users across the world and “SecurityContextHolder” contain all users token information.If user size will increase load will be more for “SecurityContextHolder”. Does “SecurityContextHolder” provide JVM clustering if user increase ?

    • I suggest you read a bit more about how spring security itself works before trying to use it for JWT based authentication.

  16. do we need to encrypt it in the user object or converting it to binary DatatypeConverter.printBase64Binary(content) is enough??

    • I suggest to stick with session cookie based authentication for your projects as this the method used in my blog requires a deeper insight of the process.