Deep Dive into Spring Security Authentication Implementation on WebFlux, Part I: Basic Authentication

Fahmi Abdulaziz
gdplabs
Published in
6 min readAug 20, 2021

--

This article is part one of two-part articles on Spring Security Authentication Implementation on WebFlux.

During the time I created my personal project with microservices architecture, I want to implement basic and JWT authentication on my Spring WebFlux project using Spring Security. Just like any other day, I just googled it. But what stumbled me at that time, is that there are only a few resources I found that give the example of how to implement it and they are all giving different solutions.

After reading all examples available online, I become more confused, because there is no explanation on the code structure. So, in this article, I want to try to give more detailed explanation on how Spring Security authentication works.

CREDIT: I want to thank everyone behind all these articles to provide free high-quality Spring Security learning materials:
1. Reactive Spring Security For WebFlux REST Web Services — A Complete (naturalprogrammer.com)
2. Spring Security 5 for Reactive Applications | Baeldung
3. raphaelDL/spring-webflux-security-jwt: A JWT authorization and authentication implementation with Spring Reactive Webflux, Spring Boot 2 and Spring Security 5 (github.com)
4. Authentication and Authorization Using JWT on Spring Webflux | by Ardiansyah | Medium

DISCLAIMER: This article is written by my limited knowledge of Spring Security, there is a chance that this article will give incomplete or wrong information.

Chain of Filters

When we add spring-boot-starter-security dependency to our Spring Boot project, the package will automatically create chain of WebFilter that every request needs to go through. We can configure the chain by creating bean of SecurityWebFilterChain.

At the example below, we allow all paths to be accessed by everyone as stated on line 12–13. We also add .formLogin() to our configuration.

What formLogin() does is basically adding AuthenticationWebFilter , one of implementation of WebFilter, to the chain of filters that process request to path/login for POST and GET method.

SecurityWebFilterChain Visualization with Added AuthenticationWebFilter

Diving on AuthenticationWebFilter

When the we send HTTP POST request to /login that has basic authentication on its header, the request will be processed by AuthenticationWebFilter . There are many processes happen behind it as shown in the image below and I will explain it one by one.

Basic authentication AuthenticationWebFilter call stacks

On the diagram above, Authentication instance passed through class stack many times. But what is Authentication instance is? It’s basically an object to save principal, credential, authority and authentication status. In this case, we will save username on and password on Authentication object’s principal and credentials field respectively. There is also authenticated field on this interface to save state whether the given credential is valid. Click here for more detailed information on Authentication interface.

In basic authentication flow case Spring Security use UsernamePasswordAuthenticationToken , implementation of Authentication interface. Click here for more information about this class.

1 — ServerAuthenticationConverter

ServerAuthenticationConverter is a FunctionalInterface that is responsible to convert data on HTTP request to Authentication object. In basic authentication flow, Spring Security use ServerHttpBasicAuthenticationConverter as implementation of ServerAuthenticationConverter .

ServerHttpBasicAuthenticationConverter will return UsernamePasswordAuthenticationToken instance with authenticated field set as false at first and pass it back to AuthenticaitonWebFilter. Later the username and password will be checked by ReactiveAuthenticationManager. If matched, authenticated field will be set to true.

ForServerHttpBasicAuthenticationConverter source code click here.

How ServerHttpBasicAuthenticationConverter convert username and password to Authentication object

2 — ReactiveUserDetailsService

ReactiveUserDetailsService is an interface that has only one method to find UserDetails by given Username. The implementation of ReactiveUserDetailsService usually take the valid credentials from database and return implementation of UserDetails .

So, what is UserDetails? it’s an interface that its implementation has valid credentials on the certain username. The commonly used implementation of this interface is User class. User object has valid credentials that will be compared to requested credentials on Authentication object.

But for the sake of simplicity, I won’t explain on how to implement ReactiveUserDetailsService that use R2DBC to get data from database asynchronously. Instead, I will use built-in in-memory implementation of this class using MapReactiveUserDetailsService like the code below.

ReactiveUserDetailsService has one method, loadUserByUsername, that will be used by ReactiveAuthenticationManager to get UserDetails object.

PasswordEncoder on this class will be injected from declared bean from next section.

3 — PasswordEncoder

On password encoder, I use built-in PasswordEncoder called DelegatingPasswordEncoder. This type of PasswordEncoder can handle different types of hash algorithm. Luckily, Spring Security gives us built-in builder for this class as shown below.

The built DelegatingPasswordEncoder object has bcrypt hash algorithm as default encoder. But it also be able to handle password that already hashed with md5, sha-1, etc. Click here to read more details on DelegatingPasswordEncoder.

This PasswordEncoder will be used to match between given password on authentication request and hashed password in UserDetailsService object.

4 — ReactiveAuthenticationManager

ReactiveAuthenticationManager is an interface that will be implemented on a class that’s responsible to decide whether the authentication request is valid. By default, when we declare .formLogin() to modify SecurityWebFilterChain it will use UserDetailsRepositoryReactiveAuthenticationManager class, one of ReactiveAuthenticationManager inheritance, by default.

This class will take unauthenticated Authentication object from AuthenticationConverter, and matched the given password and hashed password using PasswordEncoder, in this case DelegatingPasswordEncoder. The byproduct of this process is authenticated Authentication object if the authenticate method success, otherwise it will return error.

implementation of authenticate method on UserDetailsRepositoryReactiveAuthenticationManager that inherit the method from AbstractUserDetailsReactiveAuthenticationManager

The shown code above is taken from source code of built-in Spring Security AbstractUserDetailsReactiveAuthenticationManager. As you can see on line 9 of the code snippet above, it uses the injected PasswordEncoder to match the password between authentication request and hashed password on UserDetails.

5 — AuthenticationHandler

After ReactiveAuthenticationManager stack finished, the AuthenticationWebFilter will call AuthenticationHandler. In this case, we have two handlers to handle successful and fail authentication attempt. They are WebFilterChainServerAuthenticationSuccessHandler class that implement ServerAuthenticationSuccessHandler and class that implement ServerAuthenticationFailureHandler respectively.

We inject those two classes on SecurityWebFilterChain configuration as shown in the code snippet on Chain of Filters section above.

what WebFilterChainServerAuthenticationSuccessHandler do are passing the request to the next filter as shown in code below taken from Spring Security source code.

WebFilterChainServerAuthenticationSuccessHandler source code

For the ServerAuthenticationFailureHandler I just pass the implementation by using lambda expression that will respond error if it’s called.

Controller

If the request passed SecurityWebFilterChain successfully, the WebFilterChainServerAuthenticationSuccessHandler pass the request to POST /login controller. We can get the Authentication object from publisher’s context by adding Authentication parameter to controller.

On the code above, I give response contains headers with JWT Token and body with simple string. I give two option to get username on controller one from Authentication object, the other from request. I prefer to get the data from Authentication object because I think it’s more secure, but I just want to show you all the options.

Test

I sent the POST request to the server with username and password on the form as seen below.

Request and response body
Response cookie

As you can see on the images above, the response of the server is as expected. But, in cookies section, we still get SESSION cookie and the JWT hasn’t been set correctly. these problems will be explained on part two of this article.

Conclusion

This is my first time write an article about Spring, I’m really open to any suggestions and feedbacks. I hope this article will help anyone trying to implement Spring Security on Spring WebFlux.

Full source code is available on my GitHub.

--

--