Skip to main content

Command Palette

Search for a command to run...

Implementing Spring Security with JSON web token

Updated
2 min read
P

Experienced Spring Boot Developer with over 3+ years of expertise in developing scalable and high-performance web applications and microservices. Proficient in Java and Spring Boot frameworks, with hands- on experience in RESTful APIs and Microservices architecture. Adept at building secure, database-driven applications and integrating various third- party services. Strong problem-solving skills with a focus on delivering clean, maintainable, and efficient code.

Let’s start with a very basic project which has a simple @RestController UserControler. UserControler has a method mapped with @GetMapping which returns String “Hello, World!” when api ( http://localhost:8020/api/hello ) is hit.

As of now we have only added spring-boot-starter-web dependency to our project.

Let’s start by implementing Spring Security -

Step 0 → Add dependencies in pom file.

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
            <scope>provided</scope>
        </dependency>

        <!-- MySQL -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- JPA -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <!-- JWT -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.11.5</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.11.5</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.11.5</version>
            <scope>runtime</scope>
        </dependency>

Authentication and Authorization of Request happens in multiple steps -

Step 1 → Request is intercepted by the Controller

  1. Request is intercepted by “login” method which maps request data into an Object Model JwtRequest.

  2. “login” method first makes a call to “doAuthenticate” method which uses “AuthenticationManager“ to validate user. “AuthenticationManager” calls “authenticate“ method to validate user.

  3. If user is validated successfully then “login” method will generate a JWT Token for the user and return that token as response, otherwise exception with message "Credentials Invalid !!" will be thrown as a response.


@RestController
@RequestMapping("/auth")
public class AuthController {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private AuthenticationManager manager;

    @Autowired
    private JwtHelper helper;

    private Logger logger = LoggerFactory.getLogger(AuthController.class);


    @PostMapping("/login")
    public ResponseEntity<JwtResponse> login(@RequestBody JwtRequest request) {

        this.doAuthenticate(request.getEmail(), request.getPassword());

        UserDetails userDetails = userDetailsService.loadUserByUsername(request.getEmail());
        String token = this.helper.generateToken(userDetails);

        JwtResponse response = JwtResponse.builder()
                .jwtToken(token)
                .username(userDetails.getUsername()).build();
        return new ResponseEntity<>(response, HttpStatus.OK);
    }

    private void doAuthenticate(String email, String password) {
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(email, password);
        try {
            manager.authenticate(authentication);
        } catch (BadCredentialsException e) {
            throw new BadCredentialsException(" Invalid Username or Password  !!");
        }
    }

    @ExceptionHandler(BadCredentialsException.class)
    public String exceptionHandler() {
        return "Credentials Invalid !!";
    }

}

Step 2 → Configure Authentication using “AuthenticationManagerBuilder”.

  1. We have to tell “AuthenticationManager“ how to do Authentication (Ex - Basic, OAuth, JWT, etc). We do that by creating a configuration class which extends “AuthenticationManagerBuilder“ and overrides “configure” method.