Skip to main content

Command Palette

Search for a command to run...

Global State SecurityContextHolder

Updated
3 min read

Everyone agrees with the fact that having some global state is a bad idea and should be avoided. The cases in which this is really the only option are very limited. One case however, is in Spring where we get the SecurityContextHolder object. From the point of view of Spring, being a framework, this is the only way to make this information accessible to the parts of your application where you need it. This however does not mean you should rely on it everywhere in your application. In this blog post, we will explore why this is a bad idea, and what you should be doing instead.

Having some global data is not a problem in itself, as long as that data is immutable. But since the SecurityContextHolder is mutable and can be modified by everyone, everywhere makes it brittle to rely on. If you use this deep inside of your application, then you rely on the fact that the value has been set to begin with, and that this value is reliable and safe. Due to the mutable state of this object, no such guarantees can be made, making your application by definition more brittle.

Not only is your application less predictable, it also makes your application closely coupled. Every place where you rely on this object is now tied to every place where the value gets set. You need to know that if you want to use a service that relies on this object, you should make sure it is set correctly. While you can have guidelines on where to set it, it is still very easy to forget to do so. There is no compile time check that verifies this for you, and any error will only be discovered at runtime.

I have seen code, where the database layer depended on this object to make a multi-tenant system work. No need to say, that this can be very risky, if somewhere in the code the objects is modified. This could lead to the wrong data being shown to the user. If this object isn't set, you may end up with an error in your query which may be hard to debug.

Instead of relying on this SecurityContextHolder object being set deep inside of your application business logic, I propose only rely on it at the boundary of your application, that is the place where requests enter. At the edge of your application, you should handle and extract all the information required to process the request, such as user, organisation, ... and map that into your own domain object as some Principal type. This type can now be passed on to your service and used for all further processing. This approach solves all of our earlier problems. Since your service now relies on this object being passed, you are made aware your have to pass it. Moreover, by making this object immutable, you also know that the information is safe to rely on.