Form-based authentication on single page applications with Spring Security
In this post I’ll show how to change the default form based authentication behavior in Spring Security in order to adapt it to Singe Page Applications (SPA). The default workflow is as follows:
When a user accesses a protected resource without being authenticated, it redirects to the login page (Spring Security generates a page automatically for you if there is none).
When the login succeeds, it redirects to the root of the application.
On a successful logout, it redirects to http://localhost:8080/login?logout
However, on a SPA we don’t want to reload the page. Instead we will be sending the user credentials with an asynchronous call. Our desired workflow would be as follows:
Return 403 (Forbiden) if the resource is protected and user is no autenticated.
On successful login return 200 (OK). If login fails, return 401 (Unauthorized).
If you want to do the next steps by yourself you can create a new project using with Spring Initializr (https://start.spring.io/), selecting “Web”, “Security” and “DevTools” as technologies.
We create now a static resource that we want to protect, secret.txt, in the src/main/resources/static folder containing something like:
This is our secret
This resource can be accessed on http://localhost:8080/secret.txt.
In order to protect it we will configure Spring Security:
This configuration does three things:
Requires authentication in order to access the protected resource, installing a /login and /logout endpoints that follow the behavior described before.
Disables CSRF, for simplicity.
Creates a user called “user” with password “123”.
Some curl outputs follows, to demonstrate the redirection workflow:
redirecting (302) to the login page whenever an unauthenticated user requests the protected resource.
redirecting to / when the login takes place successfully, setting a JSESSIONID cookie with the id of the session created on the server.
redirecting to http://localhost:8080/login?logout when logging out.
SPA login workflow
In order to get rid of all the redirections and get the desired response codes we need to change the configuration to this:
which:
installs an exception handler to return 403 whenever an unauthenticated user accesses the protected resource. This is actually the default behavior of Spring Security, but the call to formLogin to setup form-based login overrides it.
installs success and failure handlers for login and logout. These handlers are instances of an inner class that returns in all cases a status code received as a parameter:
Now, the same curl commands as before. Note that we don’t get redirections anymore but the session management and the sending of the session cookie is still there.
An unauthenticated user requests the protected resource.