DEV Community

cuongld2
cuongld2

Posted on • Edited on

Create APIs with JWT authorization using Spring boot

Dear folks,
Today I will cover how to create simple REST APIs with JWT authorization using Spring Boot.

You might want to check out my previous blog post for How to create API using Spring and Tomcat

I've already covered how to setup MySQL, create new project in IntelliJ in the above blog post so in this blog I will skip that.

0.Create MySQL database and table using SQL query:

  • Create new database
CREATE DATABASE restapi;
USE restapi;
Enter fullscreen mode Exit fullscreen mode
  • Create new table for blog
CREATE TABLE blog (
  id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  title VARCHAR(500) NOT NULL,
  content VARCHAR(5000) NOT NULL
);
Enter fullscreen mode Exit fullscreen mode
  • Create new table for userinfo:
CREATE TABLE user_info(
  id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  username VARCHAR(50) NOT NULL,
  password VARCHAR(500) NOT NULL,
  fullname VARCHAR(50) NOT NULL
);
Enter fullscreen mode Exit fullscreen mode

1.Dependencies we will need for this tutorial:


<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.8.RELEASE</version>
    </parent>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-core -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>5.1.6.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-web -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>5.1.6.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-config -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>5.1.6.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
    </dependencies>


Enter fullscreen mode Exit fullscreen mode

We would need spring-boot-starter for create REST API.

Mysql-connector-java for connect to MySQL database.

Spring-security for setting up Authorization

jsonwebtoken for using JWT with Authorization

2.Project structure

  • resources: We will define the properties for our project in application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/restapi
spring.datasource.username=xxxx
spring.datasource.password=xxxx
spring.datasource.platform=mysql
jwt.secret={bcrypt}$donald

Enter fullscreen mode Exit fullscreen mode

spring.datasource used to provide info about your database. You would need to provide your username and password for it to work.

jwt.secret is the secret key of jwt. (I will talk about this in details later)

  • project packages:

+) config:
Used to store config files for our project.
+) controller:
Used to define controller class for Authentication, CRUD for Blog content, Create new user
+) exceptions:
Define base error handles and exception for validate data
+) model:
Create model for Blog Entity, UserInfo Entity, JwtRequest and JwtResponse
+) repository:
Create Blog and UserInfo repository to interact with MySQL database using JPA
+) service:
Create JwtUserDetailsService to check whether the username is existed in database or not

  • MainApplicationClass to run SpringBootApplication:

@SpringBootApplication
public class MainApplicationClass {


    public static void main(String[] args) {
        SpringApplication.run(MainApplicationClass.class, args);
    }

}

Enter fullscreen mode Exit fullscreen mode

3.What we will create:

  • API to create new user in the application
  • API to authen whether the user credentials is valid, if it is return token so that he or she can do other stuff
  • API to create new blog post, view blog post, or update them.

So the API for create and authenticate credentials, will not have that authorization part --> to make sure anyone can access and perform these APIs.

The API for interact with blogs will require authentication with jwt token.

To be able to do this, we would need to create configure method in our WebSecurityConfig class in config package:


httpSecurity.csrf().disable()

                .authorizeRequests().antMatchers("/authenticate","/user").permitAll().

        anyRequest().authenticated().and().

        exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()

                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);


Enter fullscreen mode Exit fullscreen mode

4.Configuration for jwt token
JwtAuthenticationEntryPoint to throw unauthorized message if the user credential is not correct


import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Serializable;

public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {

    private static final long serialVersionUID = -7858869558953243875L;

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,

                         AuthenticationException authException) throws IOException {

        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");

    }

}

Enter fullscreen mode Exit fullscreen mode

JwtRequestFilter to filter value of Authorization header:


import donald.apiwithspringboot.service.JwtUserDetailsService;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


@Component
public class JwtRequestFilter extends OncePerRequestFilter {


    @Autowired
    private JwtUserDetailsService jwtUserDetailsService;

    private final JwtToken jwtTokenUtil;

    public JwtRequestFilter(JwtToken jwtTokenUtil) {
        this.jwtTokenUtil = jwtTokenUtil;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)

            throws ServletException, IOException {

        final String requestTokenHeader = request.getHeader("Authorization");

        String username = null;

        String jwtToken = null;


        if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {

            jwtToken = requestTokenHeader.substring(7);

            try {

                username = jwtTokenUtil.getUsernameFromToken(jwtToken);

            } catch (IllegalArgumentException e) {

                System.out.println("Unable to get JWT Token");

            } catch (ExpiredJwtException e) {

                System.out.println("JWT Token has expired");

            }

        } else {

            logger.warn("JWT Token does not begin with Bearer String");

        }


        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

            UserDetails userDetails = this.jwtUserDetailsService.loadUserByUsername(username);


            if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {

                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(

                        userDetails, null, userDetails.getAuthorities());

                usernamePasswordAuthenticationToken

                        .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));


                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }
        chain.doFilter(request, response);
    }
}

Enter fullscreen mode Exit fullscreen mode

JwtToken class to generate jwt token:

@Component
public class JwtToken implements Serializable {

    private static final long serialVersionUID = -2550185165626007488L;

    public static final long JWT_TOKEN_VALIDITY = 5 * 60 * 60;

    @Value("${jwt.secret}")
    private String secret;


    public String getUsernameFromToken(String token) {

        return getClaimFromToken(token, Claims::getSubject);

    }


    public Date getExpirationDateFromToken(String token) {

        return getClaimFromToken(token, Claims::getExpiration);

    }

    public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {

        final Claims claims = getAllClaimsFromToken(token);

        return claimsResolver.apply(claims);

    }


    private Claims getAllClaimsFromToken(String token) {

        return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();

    }


    private Boolean isTokenExpired(String token) {

        final Date expiration = getExpirationDateFromToken(token);

        return expiration.before(new Date());

    }


    public String generateToken(UserDetails userDetails) {

        Map<String, Object> claims = new HashMap<>();

        return doGenerateToken(claims, userDetails.getUsername());

    }


    private String doGenerateToken(Map<String, Object> claims, String subject) {

        return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))

                .setExpiration(new Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000))

                .signWith(SignatureAlgorithm.HS512, secret).compact();

    }


    public Boolean validateToken(String token, UserDetails userDetails) {

        final String username = getUsernameFromToken(token);

        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));

    }

}


Enter fullscreen mode Exit fullscreen mode

WebSecurityConfig to define the beans we would need and config path with authentication:


import donald.apiwithspringboot.service.JwtUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;


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

    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    @Autowired
    private JwtUserDetailsService jwtUserDetailsService;

    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

        auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());

    }

    @Bean
    public JwtAuthenticationEntryPoint jwtAuthenticationEntryPointBean() throws Exception{
        return new JwtAuthenticationEntryPoint();
    }


    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();

    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {

        httpSecurity.csrf().disable()

                .authorizeRequests().antMatchers("/authenticate","/user").permitAll().

        anyRequest().authenticated().and().

        exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()

                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);

    }

}


Enter fullscreen mode Exit fullscreen mode

5.Controller:
AuthController to define the API to authenticate user credentials and response jwt token if correct:


import donald.apiwithspringboot.model.JwtRequest;
import donald.apiwithspringboot.model.JwtResponse;
import donald.apiwithspringboot.service.JwtUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;
import donald.apiwithspringboot.config.JwtToken;
import org.springframework.security.authentication.AuthenticationManager;

@RestController
@CrossOrigin
public class AuthController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtToken jwtToken;

    @Autowired
    private JwtUserDetailsService jwtUserDetailsService;


    @RequestMapping(value = "/authenticate", method = RequestMethod.POST)
    public ResponseEntity<?> createAuthenticationToken(@RequestBody JwtRequest authenticationRequest) throws Exception {


        authenticate(authenticationRequest.getUsername(), authenticationRequest.getPassword());

        final UserDetails userDetails = jwtUserDetailsService

                .loadUserByUsername(authenticationRequest.getUsername());

        final String token = jwtToken.generateToken(userDetails);

        return ResponseEntity.ok(new JwtResponse(token));

    }

    private void authenticate(String username, String password) throws Exception {

        try {

            authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));

        } catch (DisabledException e) {

            throw new Exception("USER_DISABLED", e);

        } catch (BadCredentialsException e) {

            throw new Exception("INVALID_CREDENTIALS", e);

        }

    }

}

Enter fullscreen mode Exit fullscreen mode

BlogController class to create API for create new blog, modify blog content, view blog or update blog



import donald.apiwithspringboot.model.Blog;
import donald.apiwithspringboot.repository.BlogRepository;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;

@RestController
public class BlogController {

    final
    private BlogRepository blogRepository;

    public BlogController(BlogRepository blogRepository) {
        this.blogRepository = blogRepository;
    }

    @GetMapping("/blog")
    public List<Blog> index(){
        return blogRepository.findAll();
    }

    @GetMapping("/blog/{id}")
    public Blog show(@PathVariable String id){
        int blogId = Integer.parseInt(id);
        return blogRepository.findById(blogId).orElse(new Blog());
    }

    @PostMapping("/blog/search")
    public List<Blog> search(@RequestBody Map<String, String> body){
        String searchTerm = body.get("text");
        return blogRepository.findByTitleContainingOrContentContaining(searchTerm, searchTerm);
    }

    @PostMapping("/blog")
    public Blog create(@RequestBody Map<String, String> body){
        String title = body.get("title");
        String content = body.get("content");
        return blogRepository.save(new Blog(title, content));
    }

    @PutMapping("/blog/{id}")
    public Blog update(@PathVariable String id, @RequestBody Map<String, String> body){
        int blogId = Integer.parseInt(id);
        // getting blog
        Blog blog = blogRepository.findById(blogId).orElse(new Blog());
        blog.setTitle(body.get("title"));
        blog.setContent(body.get("content"));
        return blogRepository.save(blog);
    }

    @DeleteMapping("blog/{id}")
    public boolean delete(@PathVariable String id){
        int blogId = Integer.parseInt(id);
        blogRepository.deleteById(blogId);
        return true;
    }

}
Enter fullscreen mode Exit fullscreen mode

UserInfoController to create API create new user and insert it into database with password is encoded with BCryptPasswordEncoder:

import donald.apiwithspringboot.exceptions.ValidationException;
import donald.apiwithspringboot.model.UserInfo;
import donald.apiwithspringboot.repository.UserInfoRepository;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.security.NoSuchAlgorithmException;
import java.util.Map;

@RestController
public class UserInfoController {


    final
    private UserInfoRepository userInfoRepository;

//    private HashData hashData = new HashData();

    public UserInfoController(UserInfoRepository userInfoRepository) {
        this.userInfoRepository = userInfoRepository;
    }


    @PostMapping("/user")
    public Boolean create(@RequestBody Map<String, String> body) throws NoSuchAlgorithmException {
        String username = body.get("username");
        if (userInfoRepository.existsByUsername(username)){

            throw new ValidationException("Username already existed");

        }

        String password = body.get("password");
        String encodedPassword = new BCryptPasswordEncoder().encode(password);
//        String hashedPassword = hashData.get_SHA_512_SecurePassword(password);
        String fullname = body.get("fullname");
        userInfoRepository.save(new UserInfo(username, encodedPassword, fullname));
        return true;
    }

}


Enter fullscreen mode Exit fullscreen mode

6.Exceptions:

BaseErrorHandles class for handleException as BAD_REQUEST:

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
@Slf4j
public class BaseErrorHandles {

    @ResponseBody
    @ExceptionHandler(value = ValidationException.class)
    public ResponseEntity<?> handleException(ValidationException exception) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(exception.getMsg());
    }
}

Enter fullscreen mode Exit fullscreen mode

ValidationException


public class ValidationException extends RuntimeException {

    private static final long serialVersionUID = 1L;
    private String msg;

    public ValidationException(String msg) {
        this.msg = msg;
    }

    public String getMsg() {
        return msg;
    }

}

Enter fullscreen mode Exit fullscreen mode

7.Model:
Blog model: define blog entity

@Entity
public class Blog {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String title;
    private String content;

    public Blog() {  }

    public Blog(String title, String content) {
        this.setTitle(title);
        this.setContent(content);
    }

    public Blog(int id, String title, String content) {
        this.setId(id);
        this.setTitle(title);
        this.setContent(content);
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    @Override
    public String toString() {
        return "Blog{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                '}';
    }

}

Enter fullscreen mode Exit fullscreen mode

UserInfo class to define UserInfo enty:


import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class UserInfo {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String username;
    private String password;
    private String fullname;

    public UserInfo() {
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public UserInfo(String username, String password, String fullname) {
        this.username = username;
        this.password = password;
        this.fullname = fullname;
    }

    public String getFullname() {
        return fullname;
    }

    public void setFullname(String fullname) {
        this.fullname = fullname;
    }
}


Enter fullscreen mode Exit fullscreen mode

JwtRequest model for authenticate username and password in the request in AuthController


public class JwtRequest implements Serializable {

    private static final long serialVersionUID = 5926468583005150707L;

    private String username;

    private String password;

    public JwtRequest()

    {

    }

    public JwtRequest(String username, String password) {

        this.setUsername(username);

        this.setPassword(password);

    }

    public String getUsername() {

        return this.username;

    }

    public void setUsername(String username) {

        this.username = username;

    }

    public String getPassword() {

        return this.password;

    }

    public void setPassword(String password) {

        this.password = password;

    }

}


Enter fullscreen mode Exit fullscreen mode

JwtResponse create model for token response



import java.io.Serializable;

public class JwtResponse implements Serializable {

    private static final long serialVersionUID = -8091879091924046844L;

    private final String jwttoken;

    public JwtResponse(String jwttoken) {

        this.jwttoken = jwttoken;

    }

    public String getToken() {

        return this.jwttoken;

    }

}

Enter fullscreen mode Exit fullscreen mode

8.Repository:

BlogRepository to work with MySQL database via JPA for blog table:


@Repository
public interface BlogRepository extends JpaRepository<Blog,Integer> {

    // custom query to search to blog post by title or content
    List<Blog> findByTitleContainingOrContentContaining(String text, String textAgain);

}

Enter fullscreen mode Exit fullscreen mode

UserInfoRepository to work with MySQL database via JPA for user_info table


@Repository
public interface UserInfoRepository extends JpaRepository<UserInfo,Integer> {

    Boolean existsByUsername(String username);
    UserInfo findByUsername(String username);


}

Enter fullscreen mode Exit fullscreen mode

9.Service:
Define JwtUserDetailsService for loadUserByUsername method:


@Component
public class JwtUserDetailsService implements UserDetailsService {

    @Autowired
    private UserInfoRepository userInfoRepository;


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        UserInfo user = userInfoRepository.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("User not found with username: " + username);
        }
        return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(),
                new ArrayList<>());
    }

}

Enter fullscreen mode Exit fullscreen mode

10.Run spring-boot application:
Simply run : mvn spring-boot:run

11.Interact with API using Postman:

Create new user

Alt Text

Create new user success:

Alt Text

Authenticate user credentials:

Alt Text

Authenticate user credentials success:

Alt Text

Create new blog request body:

Alt Text

Create new blog header:

Alt Text

Create new blog response:

Alt Text

That's it.
For the future tutorial, I will cover how to write unit tests and contract test for this.

You can find the sourcecode in github as usual in here

Thank you guys and girls!

Peace!!!

Notes: If you feel this blog help you and want to show the appreciation, feel free to drop by :

This will help me to contributing more valued contents.

Top comments (21)

Collapse
 
ale_jacques profile image
Alexandre Jacques

This is the first sane alternative I've seen for JWT with Spring Boot. The OAuth approach (that seems to be the "default" approach nowadays is crazy complex for a JWT authentication).
Thanks for your time and dedication.

Collapse
 
cuongld2 profile image
cuongld2

Thank you Alexandre.
Great to hear that from you!!

Collapse
 
omerfarukerkul profile image
Omer Faruk • Edited

Hello Mr. coungld2 I really liked this article and gave me new ideas but, I have a question for you. I wanted to change the database from MySQL to H2 database. I configured the server as I always do in my Spring Boot applications. I could've connected to the H2 Database console with /h2-console.
When I try to login to the /h2-console, the server gives me "JWT Token does not begin with Bearer String". I added /h2-console endpoint to the WebSecurityConfig.java as shown below.

httpSecurity.csrf().disable().authorizeRequests().antMatchers("/authenticate","/user","/h2-console/**").permitAll()

What are the steps should I take to login the database.

Thank you.
Sincerely.

Collapse
 
cuongld2 profile image
cuongld2

Dear Omer,
I'm glad that you liked this blog post.
Sorry but currently I don't have any idea about H2 database.
But I will take a look at that when I got the time.
Happy coding!!!

Collapse
 
sreedevfullstack profile image
sree-dev-fullstack • Edited

I really like the article and i have implemented the JWT token authentication in my spring boot application.it is working fine. When i tried to make it as jar and use it as dependency in another spring boot application, token authentication is perfectly happening but it is not redirecting to the Rest API.Please help me how to resolve the issue

Collapse
 
cuongld2 profile image
cuongld2

Thanks for the comment.
Sorry for late response.
I dont understand the part "not redirecting to the rest api".
Could you give more details?

Collapse
 
sreedevfullstack profile image
sree-dev-fullstack • Edited

thanks for responding. after token authentication in the JWSrequest filter

    chain.doFilter(request, response); will redirects to the restcontroller , where our request mapping url matches , our method will be executed.This redirection is not happening for me. Do i need to configure anything in security page in my application .

Can i share my code.or can you suggest the approach when we use JWt token authentication as seperate jar in other spring boot application.Here my requirement is that JWT token authentication code as seperate jar in multiple applications in my project.

Collapse
 
babusr01 profile image
SRIDHAR BABU BANDLAMUDI

Thanks for you response. This will helpful for automate restful service using restful service. Could you suggest good books or internet site to learn develop restful service using spring boot . I am core java developer .
Thanks
Sridharbabu

Collapse
 
cuongld2 profile image
cuongld2

Thank you SRIDHAR. (Not sure that's your firstname or last name so pardon me :) ).
I would suggest you take a look at Spring Boot in action book.
For online sites, please take a look at Baeldung or Dzone as they got a lot of java tutorials in general.
Cheers!!

Collapse
 
sreedevfullstack profile image
sree-dev-fullstack

thanks for responding. after token authentication in the JWSrequest filter

chain.doFilter(request, response); will redirects to the restcontroller , where our request mapping url matches , our method will be executed.This redirection is not happening for me. Do i need to configure anything in security page in my application .

Can i share my code.or can you suggest the approach when we use JWt token authentication as seperate jar in other spring boot application.Here my requirement is that JWT token authentication code as seperate jar in multiple applications in my project.

Collapse
 
cuongld2 profile image
cuongld2

Dear sree,
I've never met this situation before.
Really sorry I cannot help you on this :(.
Stay strong.
Maybe you can search online for the solution. :)

Collapse
 
gmourtzounis profile image
gmourtzounis

Hi cuongld2! Thanks for the tutorial, as a newbie in spring boot, I found it very helpful.
I have one question though. When a user signs in, a bearer token is generated; but where is it stored?
My goal is to create a log out functionality, where the user's token is destroyed upon logging out.

Collapse
 
cuongld2 profile image
cuongld2

Hi,
Im really glad that my tutorial help you :d.
The jwt token is stored in the client side.
The server will verify the token is correct or not.
Im about to add api for logout so but does not have the time yet.
If you can please make a PR to add api for log out. :)

Collapse
 
juantovarlavin profile image
juantovarlavin

Thank you so much was really helpful

Collapse
 
cuongld2 profile image
cuongld2

I'm glad this could help you.
:d

Collapse
 
sreedevfullstack profile image
sree-dev-fullstack

Can you help me how to resolve below issue.

Collapse
 
x25net profile image
x25Net

You're my hero! Thank you sir, you saved my life ;) It works like a charm

Collapse
 
cuongld2 profile image
cuongld2

So glad that could help you.
Stay tuned for more!!!

Collapse
 
jenithleon profile image
Jenith

How to get the custom header value in spring security configure method ?

Collapse
 
linhebisolvn profile image
Linh リン

tuyệt vời quá anh, trên Baeldung họ viết hơi khó hiểu hơn bài này của anh, nếu được a có thể cho link github để xem source đc ko ạ. Vì có nhiều file ko biết anh để đâu nên hơi khó implement

Collapse
 
cuongld2 profile image
cuongld2

Source code ở đây nhé Linh : github.com/cuongld2/springboot-sim...
Thanks em đã đọc bài :)