[[servlet-authentication-form]]
= Form Login
:figures: servlet/authentication/unpwd

Spring Security provides support for username and password being provided through an HTML form.
This section provides details on how form based authentication works within Spring Security.
// FIXME: describe authenticationentrypoint, authenticationfailurehandler, authenticationsuccesshandler

This section examines how form-based login works within Spring Security.
First, we see how the user is redirected to the login form:

.Redirecting to the Login Page
image::{figures}/loginurlauthenticationentrypoint.png[]

The preceding figure builds off our xref:servlet/architecture.adoc#servlet-securityfilterchain[`SecurityFilterChain`] diagram.

image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the resource (`/private`) for which it is not authorized.

image:{icondir}/number_2.png[] Spring Security's xref:servlet/authorization/authorize-requests.adoc#servlet-authorization-filtersecurityinterceptor[`FilterSecurityInterceptor`] indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`.

image:{icondir}/number_3.png[] Since the user is not authenticated, xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] initiates __Start Authentication__ and sends a redirect to the login page with the configured xref:servlet/authentication/architecture.adoc#servlet-authentication-authenticationentrypoint[`AuthenticationEntryPoint`].
In most cases, the `AuthenticationEntryPoint` is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`].

image:{icondir}/number_4.png[] The browser requests the login page to which it was redirected.

image:{icondir}/number_5.png[] Something within the application, must <<servlet-authentication-form-custom,render the login page>>.

[[servlet-authentication-usernamepasswordauthenticationfilter]]
When the username and password are submitted, the `UsernamePasswordAuthenticationFilter` authenticates the username and password.
The `UsernamePasswordAuthenticationFilter` extends xref:servlet/authentication/architecture.adoc#servlet-authentication-abstractprocessingfilter[AbstractAuthenticationProcessingFilter], so the following diagram should look pretty similar:

.Authenticating Username and Password
image::{figures}/usernamepasswordauthenticationfilter.png[]

The figure builds off our xref:servlet/architecture.adoc#servlet-securityfilterchain[`SecurityFilterChain`] diagram.


image:{icondir}/number_1.png[] When the user submits their username and password, the `UsernamePasswordAuthenticationFilter` creates a `UsernamePasswordAuthenticationToken`, which is a type of  xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[`Authentication`], by extracting the username and password from the `HttpServletRequest` instance.

image:{icondir}/number_2.png[]  Next, the `UsernamePasswordAuthenticationToken` is passed into the `AuthenticationManager` instance to be authenticated.
The details of what `AuthenticationManager` looks like depend on how the xref:servlet/authentication/passwords/index.adoc#servlet-authentication-unpwd-storage[user information is stored].

image:{icondir}/number_3.png[] If authentication fails, then __Failure__.

. The xref:servlet/authentication/architecture.adoc#servlet-authentication-securitycontextholder[SecurityContextHolder] is cleared out.
. `RememberMeServices.loginFail` is invoked.
If remember me is not configured, this is a no-op.
See the {security-api-url}org/springframework/security/web/authentication/RememberMeServices.html[`RememberMeServices`] interface in the Javadoc.
. `AuthenticationFailureHandler` is invoked.
See the {security-api-url}org/springframework/security/web/authentication/AuthenticationFailureHandler.html[`AuthenticationFailureHandler`] class in the Javadoc

image:{icondir}/number_4.png[] If authentication is successful, then __Success__.

. `SessionAuthenticationStrategy` is notified of a new login.
See the {security-api-url}org/springframework/security/web/authentication/session/SessionAuthenticationStrategy.html[`SessionAuthenticationStrategy`] interface in the Javadoc.
. The xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[Authentication] is set on the xref:servlet/authentication/architecture.adoc#servlet-authentication-securitycontextholder[SecurityContextHolder].
See the {security-api-url}org/springframework/security/web/context/SecurityContextPersistenceFilter.html[`SecurityContextPersistenceFilter`] class in the Javadoc.
. `RememberMeServices.loginSuccess` is invoked.
If remember me is not configured, this is a no-op.
See the {security-api-url}org/springframework/security/web/authentication/RememberMeServices.html[`RememberMeServices`] interface in the Javadoc.
. `ApplicationEventPublisher` publishes an `InteractiveAuthenticationSuccessEvent`.
. The `AuthenticationSuccessHandler` is invoked. Typically, this is a `SimpleUrlAuthenticationSuccessHandler`, which redirects to a request saved by xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] when we redirect to the login page.

[[servlet-authentication-form-min]]
By default, Spring Security form login is enabled.
However, as soon as any servlet-based configuration is provided, form based login must be explicitly provided.
The following example shows a minimal, explicit Java configuration:

.Form Login
====
.Java
[source,java,role="primary"]
----
public SecurityFilterChain filterChain(HttpSecurity http) {
	http
		.formLogin(withDefaults());
	// ...
}
----

.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->
	<form-login />
</http>
----

.Kotlin
[source,kotlin,role="secondary"]
----
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
	http {
		formLogin { }
	}
	// ...
}
----
====

In the preceding configuration, Spring Security renders a default login page.
Most production applications require a custom login form.

[[servlet-authentication-form-custom]]
The following configuration demonstrates how to provide a custom login form.

.Custom Login Form Configuration
====
.Java
[source,java,role="primary"]
----
public SecurityFilterChain filterChain(HttpSecurity http) {
	http
		.formLogin(form -> form
			.loginPage("/login")
			.permitAll()
		);
	// ...
}
----

.XML
[source,xml,role="secondary"]
----
<http>
	<!-- ... -->
	<intercept-url pattern="/login" access="permitAll" />
	<form-login login-page="/login" />
</http>
----

.Kotlin
[source,kotlin,role="secondary"]
----
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
	http {
		formLogin {
			loginPage = "/login"
			permitAll()
		}
	}
	// ...
}
----
====

[[servlet-authentication-form-custom-html]]
When the login page is specified in the Spring Security configuration, you are responsible for rendering the page.
// FIXME: default login page rendered by Spring Security
The following https://www.thymeleaf.org/[Thymeleaf] template produces an HTML login form that complies with a login page of `/login`.:

.Login Form
====
.src/main/resources/templates/login.html
[source,xml]
----
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
	<head>
		<title>Please Log In</title>
	</head>
	<body>
		<h1>Please Log In</h1>
		<div th:if="${param.error}">
			Invalid username and password.</div>
		<div th:if="${param.logout}">
			You have been logged out.</div>
		<form th:action="@{/login}" method="post">
			<div>
			<input type="text" name="username" placeholder="Username"/>
			</div>
			<div>
			<input type="password" name="password" placeholder="Password"/>
			</div>
			<input type="submit" value="Log in" />
		</form>
	</body>
</html>
----
====

There are a few key points about the default HTML form:

* The form should perform a `post` to `/login`.
* The form needs to include a xref:servlet/exploits/csrf.adoc#servlet-csrf[CSRF Token], which is xref:servlet/exploits/csrf.adoc#servlet-csrf-include-form-auto[automatically included] by Thymeleaf.
* The form should specify the username in a parameter named `username`.
* The form should specify the password in a parameter named `password`.
* If the HTTP parameter named `error` is found, it indicates the user failed to provide a valid username or password.
* If the HTTP parameter named `logout` is found, it indicates the user has logged out successfully.

Many users do not need much more than to customize the login page.
However, if needed, you can customize everything shown earlier with additional configuration.

[[servlet-authentication-form-custom-controller]]
If you use Spring MVC, you need a controller that maps `GET /login` to the login template we created.
The following example shows a minimal `LoginController`:

.LoginController
====
.Java
[source,java,role="primary"]
----
@Controller
class LoginController {
	@GetMapping("/login")
	String login() {
		return "login";
	}
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
@Controller
class LoginController {
    @GetMapping("/login")
    fun login(): String {
        return "login"
    }
}
----
====
