4 min read

Understanding Form Login in Spring Boot

December 15, 2020

This article explains the default behaviour of spring-boot-starter-security. In this article, we will see how to secure a simple web application with a username and password.

To start with, I have written a simple web application with an API that prints hello world.

@RestController
public class HelloController {

    @RequestMapping("/hello")
    @ResponseBody
    public String hello() {
        return "Hello World!";
    }
}

There is nothing special about this Controller. When we open http://localhost:8080/hello from the browser, we get to see a ”Hello World!” message.

Let’s add the spring security module to this project by adding the following starter dependency.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Once you have added the above dependency, Restart the application and try accessing http://localhost:8080/hello again in the browser. This time you are redirected to a Login form that asks for a username and password.

Form Login in Spring Boot

This behaviour is due to the magic of auto-configuration. Let’s dive into details.

Security auto-configuration

This starter for security does the following auto-configurations.

  1. Creates a servlet Filter called springSecurityFilterChain which is responsible for most of the security stuff like login form redirection, username password validation, session creation and destruction etc. This springSecurityFilterChain will be registered to intercept all URLs of your application.
  2. Sets up BasicAuth and a form login for all the requests. This setup is equivalent to the following.

    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .anyRequest().authenticated() 
            .and().formLogin()                      
            .and().httpBasic();
    }

    We will see these builder methods in upcoming posts.

  3. Creates a simple in-memory UserDetailService that can only allow a username called user with a generated password. This password can be found at the startup logs. Default password generated by the auto configuration This is the password that I provided in the above example.

By default, Spring Security enables a logout endpoint at http://localhost:8080/logout. On opening this URL, You will be presented with a logout Screen with a single logout button. clicking this button will log you out of the session, and a login page will be presented to you post Logout.

Default form Logout

Login flow

Here is a simple illustration of the form login works.

UserBrowserApplicationLogin FlowOpen http://localhost:8080/hello1requests content for /hello2No session exist for the user3redirect to Login page4Submits Login form5Sends POST request with credentials6Valid credentials? Yes7Create a session for the User8Here is /hello that you asked before.9Response also contains Cookie for that session This session token will be stored by browser and sent along with every future request.User gets to see "Hello world!"User asks /howdy10requests content for /howdyalong with cookie from step 911Validates cookie12Here is /howdy that you asked13User gets to see "Howdy world!"UserBrowserApplication

To understand the flow, you need to learn a little about cookies.

  1. Cookies are key-value pair with occasional expiry time associated with it.
  2. Cookies are created when the server/website/web-application sends an HTTP response with a Set-Cookie header.
  3. By design, All browsers will send cookies associated with the website when accessing any resource from that specific server/website/web-application.
  4. Websites cannot get hold of cookies from other websites.

When a login request comes to the server, the spring security logic validates the credentials and if successful, creates a session id and associates it with the logged-in user and keeps this mapping somewhere. The same session-id also sent back to the browser in the form of Set-Cookie header with the name JSESSIONID.

Now whenever the request goes to the server, the cookie will also be sent along with the request. When the server notices JSESSIONID, it can look at the session map and find appropriate user associated with that session. If no mappings found, the request will be redirected to a log in page.

Logout flow

Here is the logout flow for simple form login

UserBrowserApplicationLogout FlowOpen http://localhost:8080/logout1requests content for /logout2gives content for Logout page3User clicks Logout4Browser submits a POST request to /logout5server clears session if exists6Redirect to login page7User get to see Login page.Further requests will be redirected login pageUserBrowserApplication

In the next post, we will see how we can supply our custom login and logout pages.