Spring Boot

Implementing JWT Authentication in Spring Boot 3: A Complete Guide

By Utility Zone · 2025-11-01T16:22:25.832766

This comprehensive tutorial walks through implementing JWT (JSON Web Token) authentication in a Spring Boot 3 application with Spring Security 6. You'll build a complete authentication system from scratch with user registration, login, and token-based access control.


Step 1: Add Required Dependencies

Maven Dependencies

Add the following dependencies to your pom.xml file:12

<dependencies>
    <!-- Spring Boot Starters -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- JWT Dependencies -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-api</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>
    
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-jackson</artifactId>
        <version>0.11.5</version>
        <scope>runtime</scope>
    </dependency>
    
    <!-- Database (H2 for this example) -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>

Gradle Dependencies

For Gradle projects, add to your build.gradle file:1

dependencies {
    // Spring Security
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    
    // JJWT (Java JWT) API, Implementation, and Jackson support
    implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
    runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
    runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
    
    // Database
    runtimeOnly 'com.h2database:h2'
}

Step 2: Configure Application Properties

Add JWT configuration to application.properties:2

# Database Configuration (H2 example)
spring.h2.console.enabled=true
spring.h2.console.path=/h2-ui
spring.datasource.url=jdbc:h2:file:./testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

# JPA Configuration
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update

# JWT Properties
app.jwtSecret======================YourSecretKeyHere===========================
app.jwtExpirationMs=86400000
app.jwtCookieName=authToken

Important: The JWT secret should be at least 256 bits (32 characters) for HS256 algorithm. For production, store this in environment variables or a secure vault.3


Step 3: Create Domain Models

User Entity

package com.example.security.models;

import jakarta.persistence.*;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import java.util.HashSet;
import java.util.Set;

@Entity
@Table(name = "users",
       uniqueConstraints = {
           @UniqueConstraint(columnNames = "username"),
           @UniqueConstraint(columnNames = "email")
       })
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotBlank
    @Size(max = 20)
    private String username;

    @NotBlank
    @Size(max = 50)
    @Email
    private String email;

    @NotBlank
    @Size(max = 120)
    private String password;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "user_roles",
               joinColumns = @JoinColumn(name = "user_id"),
               inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set<Role> roles = new HashSet<>();

    // Constructors
    public User() {}

    public User(String username, String email, String password) {
        this.username = username;
        this.email = email;
        this.password = password;
    }

    // Getters and Setters
    // ... (add all getters and setters)
}

Role Entity

package com.example.security.models;

import jakarta.persistence.*;

@Entity
@Table(name = "roles")
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Enumerated(EnumType.STRING)
    @Column(length = 20)
    private ERole name;

    // Constructors
    public Role() {}

    public Role(ERole name) {
        this.name = name;
    }

    // Getters and Setters
    // ... (add all getters and setters)
}

ERole Enum

package com.example.security.models;

public enum ERole {
    ROLE_USER,
    ROLE_MODERATOR,
    ROLE_ADMIN
}

Step 4: Create Repositories

UserRepository

package com.example.security.repository;

import com.example.security.models.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByUsername(String username);
    Boolean existsByUsername(String username);
    Boolean existsByEmail(String email);
}

RoleRepository

package com.example.security.repository;

import com.example.security.models.ERole;
import com.example.security.models.Role;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;

@Repository
public interface RoleRepository extends JpaRepository<Role, Long> {
    Optional<Role> findByName(ERole name);
}

Step 5: Implement UserDetailsService

UserDetailsImpl

package com.example.security.services;

import com.example.security.models.User;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class UserDetailsImpl implements UserDetails {
    private static final long serialVersionUID = 1L;

    private Long id;
    private String username;
    private String email;

    @JsonIgnore
    private String password;

    private Collection<? extends GrantedAuthority> authorities;

    public UserDetailsImpl(Long id, String username, String email, String password,
                          Collection<? extends GrantedAuthority> authorities) {
        this.id = id;
        this.username = username;
        this.email = email;
        this.password = password;
        this.authorities = authorities;
    }

    public static UserDetailsImpl build(User user) {
        List<GrantedAuthority> authorities = user.getRoles().stream()
                .map(role -> new SimpleGrantedAuthority(role.getName().name()))
                .collect(Collectors.toList());

        return new UserDetailsImpl(
                user.getId(),
                user.getUsername(),
                user.getEmail(),
                user.getPassword(),
                authorities);
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    public Long getId() {
        return id;
    }

    public String getEmail() {
        return email;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
        @Override
    public String getUsername() {
        return username;
    }
}

<span style="display:none">45678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364</span>


<div align="center">⁂</div>

Footnotes

  1. https://ademtonay.com/posts/authentication-with-jwt-and-spring-boot ↩ ↩2

  2. https://www.bezkoder.com/spring-boot-security-jwt/ ↩ ↩2

  3. https://www.reddit.com/r/SpringBoot/comments/1kdnv1g/where_should_i_store_my_jwt_secret_instead_of/ ↩

  4. https://www.youtube.com/watch?v=_buk0CKbjUA ↩

  5. https://blog.devops.dev/spring-boot-3-spring-security-6-with-jwt-authentication-and-authorization-new-2024-989323f29b84?gi=e37f918c9c33 ↩

  6. https://www.geeksforgeeks.org/springboot/spring-boot-3-0-jwt-authentication-with-spring-security-using-mysql-database/ ↩

  7. https://stackoverflow.com/questions/74828917/maven-dependencies-for-jjwt-json-web-token-on-a-spring-boot-project ↩

  8. https://www.youtube.com/watch?v=KiYo3f7Fggs ↩

  9. https://dev.to/abhi9720/a-comprehensive-guide-to-jwt-authentication-with-spring-boot-117p ↩

  10. https://docs.spring.io/spring-security/reference/getting-spring-security.html ↩

  11. https://stackoverflow.com/questions/72715967/spring-security-implement-jwt-filter ↩

  12. https://www.toptal.com/spring/spring-security-tutorial ↩

  13. https://github.com/jwtk/jjwt ↩

  14. https://stackoverflow.com/questions/41975045/how-to-design-a-good-jwt-authentication-filter ↩

  15. https://evoila.com/blog/spring-boot-3-jwt-authentication-leveraging-spring-securitys-support/ ↩

  16. https://github.com/nomemory/spring-boot-jwt-example/blob/master/build.gradle ↩

  17. https://stackoverflow.com/questions/75791404/how-do-i-check-if-a-jwt-token-is-valid-in-spring-boot ↩

  18. https://reflectoring.io/spring-security-jwt/ ↩

  19. https://gist.github.com/abhi9720/0384b96419e7b18f7cad2d7962b84404 ↩

  20. https://stackoverflow.com/questions/77353001/spring-boot-3-jwt-token-generation ↩

  21. https://www.reddit.com/r/SpringBoot/comments/184ixyw/does_anyone_know_how_to_enable_jwt_security_and/ ↩

  22. https://github.com/ramazan/spring-boot-jwt-security-example/blob/master/src/main/java/com/ramazan/security/configuration/jwt/service/JwtUserDetailsService.java ↩

  23. https://www.youtube.com/watch?v=6EPRvCfjtKM ↩

  24. https://www.youtube.com/watch?v=oeni_9g7too ↩

  25. https://stackoverflow.com/questions/50803727/spring-with-jwt-auth-get-current-user ↩

  26. https://www.unlogged.io/post/integrating-jwt-with-spring-security-6-in-spring-boot-3 ↩

  27. https://stackoverflow.com/questions/58685218/spring-security-how-to-use-a-userdetailsservice-with-jwtauthenticationprovider ↩

  28. https://www.youtube.com/watch?v=Cj_R2hku6wE ↩

  29. https://docs.spring.io/spring-security/reference/servlet/authentication/passwords/user-details-service.html ↩

  30. https://curity.io/resources/learn/spring-boot-api/ ↩

  31. https://docs.spring.io/spring-security/reference/servlet/configuration/java.html ↩

  32. https://www.javaguides.net/2024/04/spring-security-authentication-manager.html ↩

  33. https://stackoverflow.com/questions/78836490/validate-jwt-java17-spring-security-jwt0-12-6 ↩

  34. https://www.youtube.com/watch?v=clMI_jhQcR4 ↩

  35. https://github.com/spring-projects/spring-boot/issues/11136 ↩

  36. https://github.com/Java-Techie-jt/spring-security-jwt-example/blob/master/src/main/java/com/javatechie/jwt/api/util/JwtUtil.java ↩

  37. https://www.baeldung.com/spring-security-sign-jwt-token ↩

  38. https://docs.spring.io/spring-security/reference/servlet/authentication/passwords/index.html ↩

  39. https://codersee.com/spring-boot-3-spring-security-6-with-kotlin-jwt/ ↩

  40. https://stackoverflow.com/questions/75841399/manual-login-authenticationmanager-spring-security-6 ↩

  41. https://www.codingshuttle.com/spring-boot-handbook/jwt-creation-and-verification ↩

  42. https://www.tothenew.com/blog/migrating-to-spring-security-6/ ↩

  43. https://www.youtube.com/watch?v=L9IzCEuVTzY ↩

  44. https://www.netjstech.com/2021/02/spring-boot-spring-security-jwt-authentication.html ↩

  45. https://www.reddit.com/r/SpringBoot/comments/1bd5aub/best_approach_to_implement_jwt_with_spring/ ↩

  46. https://github.com/spring-projects/spring-security/issues/11926 ↩

  47. https://igventurelli.io/javaspring-boottestingunit-testingprogramming/ ↩

  48. https://blog.tericcabrel.com/jwt-authentication-springboot-spring-security/ ↩

  49. https://dev.to/tienbku/spring-boot-login-example-eid ↩

  50. https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/jwt.html ↩

  51. https://howtodoinjava.com/spring-security/jwt-auth-vuejs-spring-boot-security/ ↩

  52. https://stackoverflow.com/questions/78197265/spring-boot-jwt-signup-login ↩

  53. https://www.youtube.com/watch?v=08kl5i8K_AA ↩

  54. https://www.youtube.com/watch?v=uZGuwX3St_c ↩

  55. https://docs.spring.io/spring-boot/appendix/application-properties/index.html ↩

  56. https://www.youtube.com/watch?v=5TY9V5xLW8o ↩

  57. https://www.reddit.com/r/SpringBoot/comments/zyrna4/how_would_i_configure_spring_security_to_return_a/ ↩

  58. https://dev.to/mspilari/spring-security-with-jwt-2bl6 ↩

  59. https://github.com/bezkoder/spring-boot-login-example ↩

  60. https://stackoverflow.com/questions/71683030/how-to-include-jwt-secret-in-application-yaml-for-java-spring ↩

  61. https://www.javainuse.com/spring/boot-jwt ↩

  62. https://stackoverflow.com/questions/53809244/difficulty-importing-jwt-json-web-token-in-spring-boot-gradle-project ↩

  63. https://ahmadkanaan.hashnode.dev/jwt-authentication-and-authorisation-using-spring-boot-3-and-spring-security-6 ↩

  64. https://www.bezkoder.com/spring-boot-jwt-authentication/ ↩