Overview Of Spring Boot REST API Security [For Beginners]

Overview Of Spring Boot REST API Security [For Beginners]

Springboot makes developing Java applications a whole lot easier and faster, but no matter how fast and easy you can build an application if it's not SECURED everything can and will go wrong.

API security cannot be overemphasized. Just like you wouldn't build a mansion without gates or doors, you shouldn't deploy an API without security.

Basic security can be divided into two:

Authentication ~ Defines who the user is.

Authorization ~ Defines what that user can do.

There are many ways you can apply API security:

  • Use tokens
  • Use encryption and signatures. Encrypt your data using a method like TLS
  • Use an API gateway

See this article for more ways.

In this tutorial, we will use JSON Web Token(JWT) which is widely used in securing APIs.

JSON Web Token (JWT) is an open standard that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret or a public/private key pair using RSA or ECDSA.

We will use three different Springboot APIs I built to explain API Security.

Basic API Without Security

A user-data API to store user data in a PostgreSQL database. Github Link

@DeleteMapping("/users/{id}")
public Map<String, Boolean> deleteUser(@PathVariable(value = "id") Long userId) throws Exception{
    User user = this.userService.getUserRepository() 
                    .findById(userId)
                    .orElseThrow(() -> new ResourceNotFoundException("User not found on :: " + userId));

    this.userService.getUserRepository().delete(user);
    Map<String,Boolean> response = new HashMap<>();
    response.put("deleted", Boolean.TRUE);

    return response;
}

The above piece of code is a DELETE request mapping with localhost endpoint localhost:8080/users/id. this piece of code DELETE's a user from the database.

If this API was deployed with URL https://userdata.com any client can perform a DELETE request https://userdata.com/users/1 and DELETE user with id 1. Ideally, you wouldn't want that.

Spring Security

Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.

Spring Security is a framework that focuses on providing both authentication and authorization to Java applications. Like all Spring projects, the real power of Spring Security is found in how easily it can be extended to meet custom requirements

spring-security does the magic.

Add the spring security dependency in pom.xml file and voilà your application is secured.

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-core</artifactId>
    <version>5.4.1</version>
</dependency>

Basic authentication takes effect in the application.

Basic API With Security

A multi-user Todo API, that allows users to create and manage Todos. Github Link, Live API docs (with swagger UI )

@DeleteMapping("todos/{todoId}")
public  ResponseEntity<Void> deleteUserTodo(@PathVariable Long todoId, Authentication authentication){
     User currentUser = userService.findUserByEmail(authentication.getName());
     Todo todo = todoservice.getTodoByUserAndId(currentUser, todoId);

     todoservice.deleteTodo(todo,currentUser);
     return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}

See the request parameter Authentication. This class gets the current application Security context holder(Current logged in User) docs.

The controller logic finds todoById associated with that logged-in user if found deletes that todo else throws ResourceNotFoundException.

The Security context holder is gotten from the JWT token sent via Authorization headers. The image below explains how the JWT token is created and sent.

JwtFlow.png Image Source: Xoor Medium Blog

OneToMany database entity-relationship exists between User(one) and Todos(many). User with id "2" cannot DELETE the todo of user with id "1" or any other user and vice-versa.

Basic API With Role-Based Security

Role-Based Security:

Role-based access control (RBAC) is a method of restricting network access based on the roles of individual users within an application.

Imagine an internal Company web application, a junior employee will not have the same access-level as a manager.

At some point in an API, role-based access will be added. This defines who is authorized to do what and who isn't.

HttpSecurity: Which is global and is by default applied to all requests.

Method-level security is implemented by adding a set of annotations on controller methods. These annotations contain a Spring Expression Language (SpEL) snippet that is assessed to determine if the request should be authenticated.

HttpSecurity

protected void configure(HttpSecurity http) throws Exception {
    http.cors().and().csrf().disable().authorizeRequests()
        .antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll()
        .antMatchers("/v2/api-docs",
               "/configuration/ui",
               "/swagger-resources/**",
               "/configuration/security",
               "/swagger-ui.html",
               "/webjars/**").permitAll()
        .anyRequest().authenticated()
        .and()
        .addFilter(new JWTAuthenticationFilter(authenticationManager()))
        .addFilter(new JWTAuthorizationFilter(authenticationManager())).sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // this disables session creation on Spring Security
}

This code configures HttpSecurity for the entire Multi-User Todo application.

.antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll()
                .antMatchers("/v2/api-docs",
                "/configuration/ui",
                "/swagger-resources/**",
                "/configuration/security",
                "/swagger-ui.html",
                "/webjars/**").permitAll()

This code permits to access the API docs and "/signup" endpoints while all other endpoints are authenticated.

To implement Role-Based Authorization using HttpSecurity .antMatchers("/endpoint1","endpoint2" //and so on)

To Implement Role-Based Authorization using Method-Level Security use @PreAuthorize annotation and other annotations from the set containing Spring Expression Language (SpEL) snippet @PreAuthorize("isAuthenticated()")

HttpSecurity is tied to URL endpoints while @PreAuthorize is tied to controller methods and is located within the code adjacent to the controller definitions. { Source }

Having all of your security in one place and defined by web endpoints has a certain neatness to it, especially in smaller projects, or for more global settings; however, as projects get larger, it may make more sense to keep the authorization policies near the code being protected, which is what the annotation-based method allows.{ Source }

Method-Level Security

Finally, we can look into API 3, A role-based user API that sends user details, authorities etc via JWT Token payload. Github Link.

@PreAuthorize("hasRole('ADMIN')")
@DeleteMapping("/users/{userId}")
public ResponseEntity<Void> deleteUser(@PathVariable Long userId){
    User user = userService.findUserById(userId);
    if (user == null){
        return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }
    userService.deleteUser(user);
    return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}

Only a User with Role ADMIN can access the endpoint above.

Method-Level Security can be activated by adding @EnableGlobalMethodSecurity (prePostEnabled = true) annotation to the SecurityConfig class.

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

     // WebSecurity Configurations


}

Summary

Security, in general, is one of those topics that none of us has a full understanding of how it works, but yet we need to secure our applications in one way or the other.

Spring Security has evolved over the years and I hope this is a good overview of Spring Boot REST API Security. This is my first technical article, I hope it met you well.

Resources that go in-depth into REST API security with Spring-Security.

Spring Security | FULL COURSE

Spring Boot Token-based Authentication with Spring Security & JWT

REST Security with JWT using Java and Spring Security

Spring Method Security with PreAuthorize

Spring Boot API Security with JWT and Role-Based Authorization