Important Concepts in Spring Boot Security (Authentication, Authorization, CORS, CSRF, OAUTH2, JWT e.t.c)

Adeola Oni
23 min readMar 27, 2021

Security is the act of keeping data and information safe from attacks like broken authentication, CSRF, cross-site phishing, injection attacks e.t.c. Web application protection is a subset of information security that focuses on website, web application, and web service security. Web application protection, at the most fundamental level, is based on application security standards, but it applies them directly to the internet and web systems.

Requirements

The requirements for understanding and running the code are: Basic knowledge of Spring Boot terms and concepts, an IDE(integrated development environment), postman, a browser, and an open mind.

Sample project without security

To start, we will generate a simple Spring Boot application without security by using spring initializr or spring tool suite. The dependencies to be added are “spring web”, and “spring devtools”.

Sample Image of the dependencies to choose

Create a controller package and create a class in the controller.

HelloController.java

For this write-up, i will be creating a controller in src/main/java. My controller will be called Controller. I will create a class in the controller called HelloController.

Go back to the main class and add a reference to the HelloWorld Controller by adding @ComponentScan(“com.adeola.security.controller”)

EmployeeSampleApplication.java

@ComponentScan annotation enables component scanning in Spring.

When you run the java application the console will specify the port where the application is running on. E.g http://localhost:8080 Append the path specified in the get mapping and run it on http://localhost:8080/hello

The browser will display the text specified by that path. In this case, it is “Welcome to the first application without security”.

1. SPRING SECURITY

We shall start this section by adding security to the sample project above. Open the project’s pom.xml and add spring-boot-starter-security dependency to it.

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

After adding this dependency, it will be downloaded to the maven folder. Re-run the application again and you’ll see two things change:

a). The URL changes from http://localhost:8080/hello to http://localhost:8080/login

b). A login page is created by the spring-boot-starter-security.

http://localhost:8080/login

Spring Boot does an immediate security configuration.

The default username is “User”. The default password will be written on the console. After signing in, you’ll see the same text we had before the addition of security, “Welcome to the first application without security”

We can remove the default username and default password by explicitly stating what our username and password should be. This can be done by adding the new username and password in the application.properties file.

application.properties

Re-run the application. Enter the new application username and password.

How to keep a user logged in

How does the browser keep user information and password when you refresh the page? You will notice that if you refresh http://localhost:8080/welcome the browser will take you back to the login page. This is not a useful behavior. When logged into Netflix, Gmail, or Youtube you stay logged in. How can we implement this behavior in our Spring application?

Whenever you make a request to the spring security server it assigns a token (registration id) for all further requests, therefore we do not have to store the user credentials(keeping user credentials is a security issue). Whether the user credentials are valid or not, a SESSIONID is generated and stored at the spring container level. This SESSIONID helps in keeping a user logged in.

What do we do when we have paths that do not require authentication?

The most important class in spring security framework is WebSecurityConfigurerAdapter . We use it to override the in-built default configuration.

Spring framework default configuration

The default configuration is that any request, form login or HTTP basic that gets sent to the spring server has to be authenticated anyRequest().authenticated(). To change this default configuration, we will create another package called config and create a class for the new configuration.

EmployeeSampleApplication.java

Kindly add your configuration package location using @ComponentScan. This will enable the application to read the customization we made via the configuration class.

For the sake of clarity, we’ll make an application for EMPLOYEES. In the sample application, we will have 4 endpoints, which are: “/home”, “/about”, “/booking” and “/balance”. Let us assume that the endpoints “/home” and “/about” require no authentication. We can distinguish between the pages that require authentication and those that do not by editing the config class created in the config package.

EmployeeSecurityConfig.java

We changed the default configuration. We used .antMatchers() to find the paths to authenticate and .permitAll() for paths that do not require authentication.

NOTE: The classes for home, about, booking, and balance should be created with their respective @GetMapping()

Example:

HomeController.java

2. USER DEFINITION AND MANAGEMENT

We can choose not to use the user credentials in the application.properties by creating our own user definition in the configuration class (EmployeeSecurityConfig.java). This can be done by using inMemoryAuthentication() or InMemoryUserDetailsManager(). For both methods, we will need a password encoder. They both do the same thing but InMemoryUserDetailsManager() is neatly written and well organized.

Configuring a user through inMemoryAuthentication()

inMemoryAuthentication() of EmployeeSecurityConfig.java in the config package

Configuring a user through InMemoryUserDetailsManager()

InMemoryUserDetailsManager() of EmployeeSecurityConfig.java in the config package

User Management in Spring Security

UserDetails: Whenever we are authenticating or authorization we need the user details of the consumer of our service. UserDetails is an interface that defines the schema of the user that will use our application. It has various inbuilt methods like getPassword(), getUsername(), getAuthorities(), isAccountNonExpired(), isAccountNonLocked(), isAccountNonExpired, isCredentialsNonExpired() and isEnabled(). These are needed for spring security to know if the user is valid.

UserDetailsService: This interface has a single inbuilt method, loadUserByUsername(). The method validates if the given user is present in our database or memory of the spring container by trying to fetch the user. The return type of loadUserByUsername() is UserDetails, which has been explained above.

https://docs.spring.io/spring-security/site/docs/3.2.x/apidocs/org/springframework/security/core/userdetails/UserDetailsService.html

UserDetailsManager: This interface is used when we have a requirement to fetch and also maintain the user details. UserDetailsManager has various inbuilt methods for fetching and maintaing user details, such as createUser(), updateUser(), deleteUser(), changePassword() and userExists(). It also has the loadUserByUsername() method because it extends UserDetailsService.

UserDetailsManager Methods, https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/provisioning/UserDetailsManager.html

There are three popular spring implementations of UserDetailsManager. They are:

a. InMemoryUserDetailsManager: This maintains, creates, and fetches user details from the memory of the spring container. The application details, authorities, and log are in-memory.

b. JdbcUserDetailsManager: loads all codes related to creating, updating, deleting a user from the database. Let us create a database to store user details and leverage jdbcUserDetailsManager to validate user details in the database during the authentication process. It is more advanced and has production-ready methods which makes it better than InMemoryUserDetailsManager().

c. LdapUserDetailsManager: If users are maintained on a LDAP server, we use this. It is based around a common configuration in which users and groups/roles are stored in different contexts, which are specified by the “userDnBase” and “groupSearchBase” properties. This class can be used in place of any other UserDetailsService for authentication in this case since LDAP is only being used to retrieve information

Implementation of UserDetailsManager

a. Create an RDS (Relational Database Server) on AWS and connect it to MySQL Workbench or Sqlectron. How to Connect AWS RDS with MySQL Workbench: http://www.youtube.com/watch?v=fhDhfG9MEF8

b. Create a database and a table. Populate the table.

Sqlectron

We are creating a table (users) in the employeeDB. Add a user to the users’ table.

c. To make use of JDBC for authentication, kindly add the maven dependencies for spring-boot-starter-jdbc, mysql-connector-java, and spring-boot-starter-data-jpa in the pom.xml.

pom.xml

d.Edit the application.properties, the URL should point to your AWS RDS endpoint concatenated with the name of the database created with Sqlectron or MySQL Workbench. The username and password should be the ones used to create the MySQL RDS.

When you run the application again, you will only be allowed to login via the credentials stored in the users’ table of the DB.

application.properties

e. Create a custom UserDetailsService. What happens when we want our login credentials to be different from the generic ones required by UserDetailsService? We create our own! In this example, we will create our own by using JPA repository to perform crud operations to the database.

How to create a custom UserDetailsService.

Step 1: Create a hotel_guest table in the database

Sqlectron

Create a table “employee” in the database and add the employee_id, email, password, and roles columns to it. Insert dummy data into the table as shown in the image.

Step 2: Create a JPA class in a package(“model”)

Employee.java

Step 3: Create a Service that implements UserDetailsService

EmployeeUserDetails.java

EmployeeUserDetails Service implements UserDetailsService. The default authentication provider (DAO Authentication Provider) will call loadUserByUserName, which will go to the database and use the passwordEncoder and before returning to the provider after successful authentication. Subsequently, the provider will convert from user details to authentication.

Step 4: Create a CRUD Repository in a package (“repository”)

EmployeeRepositoy.java

This will help to perform crud operations on the table. It extends CrudRepository provided by the spring framework. The beauty of JPA is that you don't have to write methods to perform certain commands. JPA has ready-made implementations of various abstract methods.

Step 5: In order to help Spring Security understand what Employee is(in Step. 2), we have to create an Employee that implements UserDetails.

https://docs.spring.io/spring-security/site/docs/4.2.20.RELEASE/apidocs/org/springframework/security/core/userdetails/UserDetails.html

Recall that UserDetails is a container for core user information. They simply store user information which is later encapsulated into Authentication objects.Create a user representation of the Employee table in the DB that implements UserDetails

SecurityEmployee.Java

Step 6: Implement UserDetailsService not UserDetailsManager

We are not using UserDetailsManager Interface because we are not yet creating, changing, deleting, or updating the password. We only need the LoadUserByUsername() method to validate the user.

EmployeeUserDetails.java

Create an EmployeeUserDetails class that implements UserDetailsService in the config package. In the EmployeeSecurityConfig, remove the UserDetailsService Bean because the new HotelGuestUserDetails will be replacing it.

EmployeeSampleApplication.java

In the main application add @EnableJpaRepositories annotation to scan for all repositories present and @EntityScan annotation will help to scan all entities

Stop the running application and use the email and password from the employee table in the database.

Example: email=raymondreddington@example.com password= 56789

3. PASSWORD MANAGEMENT AND ENCODER

When a user enters their credentials, spring takes the username and calls loadByUsername which includes user details and the password. It goes ahead to check if the passwords match. If it does not match it will call a 401 error. The main issue with this method is that user details and credentials are stored plainly in the database. This is wrong because anyone can see the credentials and password is sent in plain text over the network.

We can improve upon this security issue by encoding, encrypting, or hashing our password.

Encoding is a mechanism of converting data from one form to another using an algorithm. It lacks authenticity, anyone can decode the data when they use the same algorithm to decode it. It is not advised to use encoding for sensitive data. Examples are UNICODE, ASCII and BASE64.

Encryption is more advanced than encoding, we use an algorithm with a secret key for encryption. To decrypt the original data, a secret key is required. We have Symmetric and asymmetric encryption. In Symmetric encryption, both encryption and decryption use the same secret key. In Asymmetric encryption the decryption and encryption key are different. Examples are TLN, VPN, SSH.

Hashing is the most suitable mechanism for password management. It is irreversible by other users. The hashing function hashes the data given to it and generates a hash value.

A password encoder is responsible for validating the user, it will tell spring what password hashing mechanism has been used. So that the same mechanism will be used to hash the inputted password. if both hash values match, the login will be successful.

Types of password encoders

a). NoOpPasswordEncoder: This password encoder has no security measure in place. It takes the raw password and compares it to the password stored. If they match, it returns boolean true. This is not a good practice because the password is stored in plain text. There is no encryption or hashing mechanism in place.

b). StandardPasswordEncoder: This password encoder decodes the hashed password and extracts the salt from the resulting byte array. It will use the salt to provide a plain-text password in which you have entered. If the resulting hash matches the initial hash, your passwords will match! Refer to the source for information

c). BCrypt and SCrypt Password Encoder: BCryptPasswordEncoder uses a powerful BCrypt hashing function to encrypt a password while SCryptPasswordEncoder uses a SCrypt hashing function to encrypt a password.

d). Pbkdf2PasswordEncoder: Password-Based Key Derivation Function 2 is an easy slow-hashing function that performs an HMAC (Hashed-Message Authentication code) as many times as defined by the iteration statement.

Implementation of the BCrypt Password Encoder:

The password saved in the database will be the hashvalue of the inputted value in BCrypt algorithm.

EmployeeSecurityConfig.java

Replace NoOpPasswordEncoder() with BCryptPasswordEncoder().

To get a full understanding of how the BCryptPasswordEncoder() works, kindly visit https://bcrypt-generator.com/ choose a string to encrypt and copy the encrypted string.

https://bcrypt-generator.com

Go to your Sqlectron or MySQL Workbench and create a new employee with an email and use the encrypted string as the password. I hashed the string ‘flash’ to get the Bcrypt encrypted hash below:

Sqlectron

Go to the login page and try logging in with the string you hashed. It works!! I hashed the string ‘flash’ to get the Bcrypt encrypted hash. The value is stored in the employee table along with the email and role. When trying to log in, I used ‘barryallen@example.com’ as my email and ‘flash’ as my password.

How does this work? The BCryptPasswordEncoder has an inbuilt method called matches(), which compares the encrypted value of the password you input to the encodedPassword.

ByCryptPasswordEncoder inbuilt function matches()

4. AUTHENTICATION PROVIDER

The usual pattern of spring security authentication providers is to use UserDetailsService to find a user and PasswordEncoder to validate the password. In some cases, we might want to use something different like OTP (one-time pin) code, fingerprint, or face recognition. We could also decide to use all three authentication providers based on the command from the authentication manager. It has two inbuilt methods:

a). Authenticate(): We use this approach to describe the rationale for authentication. Receives an Authentication Object as a parameter and returns an Authentication Object as well.

b). Support(): The support method specifies which type of authentication format that the AuthenticationProvider supports e.g username and password, OTP, fingerprint or face recognition.

https://docs.spring.io/spring-security/site/docs/4.2.20.RELEASE/apidocs/org/springframework/security/authentication/AuthenticationProvider.html

Previously we used an EmployeeUserDetails Service that implements UserDetailsService. The default authentication provider (DAO authentication Provider) calls loadUserByUserName() which goes to the database and leverages on the passwordEncoder and once authentication is successful userDetails will be sent back to the provider. Afterward, the provider performs the conversion from userDetails to authentication. This is the UserDetails(), UserDetailsService() and UserDetailsManager() trio.

Implementation of a custom AuthenticationProvider

We will create a new class that implements a custom AuthenticationProvider and performs authentication easily.

EmployeeRepository.java

Get username and password from the authenticationObject from the principleInterface. We will search for the employee in the employeeRepository and leverage the passwordEncoder to see if the hashvalue of the received password is the same as what is stored in the database.

If all matches, populate the authorities based on the role in the employee object and create a UsernamePasswordAuthenticationToken.

The Support() method specifies whenever we get an input of type UsernamePasswordAuthenticationToken (username and password combination), it should use the EmployeeUsernamePasswordAuthenticationProvider method.

Restart the java application to see the changes made.

5. CORS(CROSS-ORIGIN RESOURCE SHARING) AND CSRF(CROSS-SITE REQUEST FORGERY)

Cross-Origin Resource Sharing(CORS) is a protocol that enables scripts running on a browser client to interact with resources from a different origin. It is not a security issue or an attack, it is the default protection provided by browsers to stop sharing data between different origins. Different origins include different schemes (HTTP or HTTPS), domains, or ports.

When the server has been configured properly to allow CORS some special headers will be appended. The presence of these headers will determine if the request supports CORS.

Initially, the browser will send a preflight request to the backend server to determine if it supports CORS, the server then responds to the preflight request with a collection of headers.

Access-Control-Allow-Origin: defines which origins can have access to the resource.
Access-Control-Allow-Methods: indicates which HTTP methods (POST, GET, OPTIONS, DELETE) for cross-origin requests.
Access-Control-Allow-Headers: indicates the allowed request headers for cross-origin requests.
Access-Control-Allow-Credentials: indicates whether or not the response to the request can be exposed when the credentials flag is true.
Access-Control-Max-Age: determine the expiration time of the result of the cached preflight request.

(Read for more understanding on preflight requests: https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request)

From the explanation above, you’d see that we need to configure CORS in our Spring Boot application.

EmployeeSecurityConfig.java

Connect your front-end to the server. In the example above my React app was running on http://localhost:3000, change the SetAllowedOrigins to the port of your UI respectively.

Cross-Site Request Forgery (CSRF or XSRF) attack attempts to conduct an action in a web application on behalf of a customer without their prior permission. It happens when performing requests(PUT, POST, DELETE) that result in data change in the database.

Example: If I use my credentials to log in to Amazon’s website, my browser will retain an active session/cookie. After that, if I visit a blog that includes a malicious link and click on the link, the browser’s cookie sends a message to Amazon to update my password. This is considered a genuine request because of the correct cookie that was generated.

CSRF protection can be implemented by disabling it in spring security or maintaining a CSRF token.

Fixing CSRF error by disabling it in spring security

EmployeeSecurityConfig.java

Fixing CSRF error by maintaining a CSRF token

The CSRF token is generated when a user logs in and is not stored in the browser session/cookies. The token will be given to the caller(browser or UI) and make sure that the token value is passed also when a connection to the server needs to be created. If a valid CSRF token is not passed, the server will block the connection and return an HTTP 403 error.

EmployeeSecurityConfig.java

By default the token (XSRF-TOKEN) will be generated by CookieCsrfTokenRepository and withHttpOnlyFalse() sends the token to the UI in a format that can be understood by the UI. While ignoringAntMatchers() allows us to ignore certain paths.

6. AUTHENTICATION, AUTHORIZATION AND ROLES

Authentication involves the identification of a user before giving access. It is done by using the user’s login details and failure to authenticate a user gives an HTTP 401 error. It is usually done before authorization.

Authorization involves checking a user’s authorities before giving access to certain resources. It usually checks for the user’s privilege or roles.

When the client makes a request with the credentials, the authentication filter intercepts the request and validates the user. After successful authentication, the authentication filter stores the UserDetails in the SecurityContext. The UserDetails will contain the username and authorities. The authorization filter also intercepts and decides on what accesses/paths the user is allowed based on the authorities in the SecurityContext.

A single user can have multiple authorities/roles. The authority of a user can be configured and validated using the following:

a. hasAuthority(): Accepts a single authority for which the endpoint will be designed, and the user will be checked against the defined authority.
The endpoint can only be accessed by those who have the same authority configured.

b. hasAnyAuthority(): Accepts several authorities for which the endpoint will be configured and the user will be verified against the authorities listed.
The endpoint can only be accessed by users who have all of the configured permissions.

c. access(): This uses Spring Expression Language (SpEL) which provides you with an infinite number of options for configuring authorities, which are not available with the previous approaches.

NB: Any route that is unauthenticated cannot be authorized.

EmployeeSecurityConfig.java

We can add authority to paths that require authorization by changing .authenticated() to .hasAuthority() . If it doesnt require authorization, simply leave it as .authenticated().

Sqlectron

Create a table called ‘authorities’ in our employee database. Assign read and write to an employee already at the employee table. I choose employee with the id = 2, because my record for ‘barryallen@example.com’ has the id, 2.

Employee.java

After the database configuration of authorities, we will do a JPA configuration inside the employee entity we have to create a one-to-many mapping between customer and authorities.

Furthermore, generate the getter and setter for the authorities.

EmployeeUsernamePasswordAuthenticationProvider.java

The ‘EmployeeUsername — PasswordAuthentication — Provider’ has to change a few things to accommodate the changes we have made with respect to using authorities. Instead of .getRole() we will use the new helper method called .getGrantedAuthorities().

To visibly see the effect of the changes that .hasAuthority() and has made, you can create a new employee without the accepted authorities for certain paths and see the error

You would have noticed that we have used ROLES and AUTHORITIES, and you may be wondering what is the difference?

Authorities are individual privileges such as READ, WRITE, UPDATE or DELETE, while a Role is a group of privileges. A Role has to have a ROLE_ prefix such as ROLE_ADMIN or ROLE_USER.

Roles are very similar to Authorities in functions. The Roles of a user can be configured and validated using the following:

a. hasRole(): Accepts a single role name for which the endpoint will be configured, and the user will be checked against the defined role.
The endpoint can only be accessed by those who have the same role configured.

b. hasAnyRole(): Accepts several roles for which the endpoint will be configured and the user will be verified against the roles listed.
The endpoint can only be accessed by users who have all of the configured roles.

c. access(): This uses Spring Expression Language (SpEL) which provides you with an infinite number of options for configuring roles, which are not available with the previous approaches.

Update the authorities Table in the database to show Roles and change the EmployeeSecurityConfig and change from using authorities to roles.

Sqlectron
EmployeeSecurityConfig.java

7. FILTERS

When we need to perform some external tasks during authentication and authorization, we use Spring security HTTP Filters. Some of these external tasks include: Encryption, decryption, input validation, multi-factor authentication using OTP e.t.c Filters are servlet concepts that receive requests, process their logic, and handover to the next filter in the chain.

Spring Boot has various internal filters such as CsrfFilter, CorsFilter, LogoutFilter, SessionManagementFilter e.t.c

To create our customized filter we have to implement the filter interface from the javax.servlet.package and override the doFilter() method. The customized filter method will receive the following parameters:

ServletRequest: This object is used to get the details of the HTTP request from the client.

ServletResponse: This object is used to modify the response before sending it back to the client or the next filter.

FilterChain: This depicts a collection of filters with a defined order. The FilterChain object is used to forward the request to the next filter in the chain.

The methods used to configure a custom filter into spring security flow are:

a. addFilterBefore(filter, class): This adds a filter before the defined filter class’s location.

CheckBeforeFilter.java

We will create a filter package in our project and configure custom filters into our spring security flow. Our first filter will use the method addFilterBefore to check if the email we are using to log in has the word “test” in it. As a developer, it is quite common to use that word often.

b. addFilterAfter(filter, class): This adds a filter after the defined filter class’s location.

LogAfterFilter.java

In the filter package, we will create another filter to explain the addFilterAfter(). Create a class LogAFterFilter() that logs details and authorities after successful authentication.

c. addFilterAt(filter, class): This adds a filter at the defined filter class’s location. It will not replace the filter already positioned there. There is no way to specify the order for multiple filters at the same location, so it has a random approach.

LogAtFilter.java

Create a LogAtFilter() the filter package. This filter Logs “Authenticating…” while authentication is ongoing.

Add the filters in the EmployeeSecurityConfig class as shown below and restart the java application to see the effect of the CheckBeforeFilter(), LogAFterFilter() and LogAtFilter().

EmployeeSecurityConfig.java

8. TOKEN BASED AUTHENTICATION USING JSON WEB TOKEN (JWT)

A token can be a plain string of format universally unique identifier (UUID) or it can be of type JSON Web Token (JWT) usually that gets generated when the user authenticated for the first time during login. When a request is sent to a restricted resource, the client sends the access token in the query string or Authorization header. The server then validates the token and, if it is valid, returns the secure resource for the client.

JWT can be used beyond authentication and authorization, it can be used for information sharing or storing in the token rather than the server memory. This is so that it won’t degrade the performance of the server over a period of time. JWT has three parts separated by dots, they are:

Header: This contains the metadata related to the token. If there is a signature in the token, it(the header) will also contain the name of the algorithm that generated the token.

Payload: This contains the details of the user, the roles e.t.c

Signature(Optional): This is optional if the receiver of the JWT is internal, but compulsory if the service will be used by different users over an open web. The reason for this is that we do not want users to tamper with header and payload details such as authorities, roles, and secure user details.

In our sample project, we will enhance our application to use JWT.

a. Edit your pom.xml by adding the following dependencies:

pom.xml

b. Disable the CSRF in the employee security configuration. This is because JWT is a token that can validate the caller’s token, enabling the CSRF is redundant.

Recall that there is a JSESSIONID always created by the spring security framework whenever you log in. This ID is stored in the HTTP session of the server. You can view this by using your browser’s developer tools.

EmployeeSecurityConfig.java

SessionCreationPolicy — .STATELESS means that the configuration should use the stateless security session creation policy. This means that the spring security framework should not create any HTTP session and tokens. When we generate a JWT token, we will send the authorization in the header. Then we will configure setExposedHeaders(), which allows the header to visible to the client consuming the backend services.

Creating JWT Token Generators and validators

We will be creating two simple filters, one for generating JWT tokens and the other for validating the tokens for every request coming from the client.

JWTTokenGeneratorFilter

JWTTokenGeneratorFilter.java

This filter will only run once per request because it extends OncePerRequestFilter. We also use the shouldNotFilter, which makes sure that the filter should not be implemented during the login process.

How is the token generated? Once authentication is successful, the authentication values are fetched from the SecurityContextHolder and we can use a secret key stored in a constant file.

SecurityConstants.java

inside the JWT token, we have to set some details such as the issuer, subject, claims, expiration time for the token e.t.c Once we have the JWT encoded values with the signature key, we will set that inside the response header JWT_HEADER with the value ‘Authorization’.

JWTTokenValidatorFilter

JWTTokenValidatorFilter.java

It validates the JWT token that got generated. A shouldNotFilter method will make sure that the filter is not applied when logging in. It will be applied to all other paths. The UI has to send the same token value in its request header with the same name ‘Authorization’. Once we have a JWT token with the same secret key we will generate a new hash value that we will compare with the hash value present in the JWT token to make sure that the values are not corrupt. If there is a mismatch an exception will be thrown.

9. OAUTH2

The OAUTH2 protocol is a straightforward delegate protocol.
It helps a third-party software program to access services on the owner’s behalf by orchestrating an acceptance relationship between the owner and the third-party in a way that prohibits the third-party from impersonating the owner.

In HTTP Basic authentication, the client sends the user credentials and authentication logic has to be executed every time with all the requests. As a result, the user credentials are shared across the network. The OAUTH2 tries to solve this problem of the sharing of user credentials over the network by leveraging token-based authentication and authorization.

OAUTH2 can also be used to avoid duplicating authentication flow, authorization flow e.t.c. It does this by placing all the authentication and authorization flows in a different server.

OAUTH2 can also be used to prevent user credentials mismanagement by third-party applications.

We can build our own authentication server, but for this example, we will be using the GitHub OAUTH2 authentication server.

Steps to create a GitHub OAuth application:

Github

Sign in on GitHub, go to settings, go to Developer settings, go to Auth Apps and register a new Auth application.

Register your application to see the ClientID and generate the Client secret

Github

Implementing OAUTH2

a. For this example, create a new Spring Boot starter project and add the dependency below to your pom.xml

pom.xml

b. Create a rest controller with path “/”. Whenever the redirection from the localhost:8080 happens and authentication is successful, the page will be redirected to SecuredPage.html

PathSecurityController.java
SecuredPage.html

It is safe to assume that SecuredPage.html is a protected resource inside the server. Whoever needs to use this resource needs to successfully login using the Github OAuth.

c. Create a config package and create a class for the configurations.

OauthGithubConfig.java

The overridden configure method will ensure that any request inside the application has to be authenticated and it has to use oauth2Login().

Whenever you try accessing SecuredPage.html you will be required to input your GitHub credentials.

CommonOauth2Provider() is a class provided by the spring security framework team, it consists of the most common oauth2 servers e.g GOOGLE, GITHUB, FACEBOOK, and OKTA.

ClientRegistrationRepository is the same as userDetailService, in regular authentication. It has a method findByRegistrationId() that gets all the configure client registration details.

Restart your application and you’ll see an interface like this:

Github

Authorize yourself and see your html page.

If you successfully followed my teachings to this point, kindly CLAP!!! I hope i have been able to shed some light and help you understand more!!! Goodluck!

--

--