DEV Community

Cover image for πŸ” Spring Security: Using JWT and Basic Auth for Different URL Patterns
JavaFullStackDev.in
JavaFullStackDev.in

Posted on • Edited on

πŸ” Spring Security: Using JWT and Basic Auth for Different URL Patterns

Hello, fellow developers! πŸ‘‹

If you've ever scratched your head wondering, "How can I use both JWT and Basic Auth in the same Spring Boot application for different URL patterns?" β€” you're not alone. This blog post is for developers like you who want to secure different parts of a Spring Boot app using different authentication mechanisms.


By the end, you'll be able to:

βœ… Secure some APIs with Basic Auth

βœ… Secure others with JWT

βœ… Configure everything cleanly with Spring Security

Let’s dive right in!


✨ Why Would You Need Multiple Authentication Types?

There are plenty of real-world use cases:

  • Public APIs secured via Basic Auth (for clients using tools like Postman or curl)
  • Mobile/web clients using JWT tokens for stateless authentication
  • Admin endpoints that are locked down with Basic Auth
  • User endpoints that use JWT-based login flow

Instead of choosing either JWT or Basic Auth, Spring Security gives us the power to use both, tailored to specific URL patterns.


🧠 High-Level Approach

Here’s how we’re going to do it:

  1. Create two SecurityFilterChain beans:
    • One for Basic Auth endpoints (/api/admin/**)
    • One for JWT-secured endpoints (/api/user/**)
  2. Define an authentication provider for each type.
  3. Register both configurations with proper @Order.

πŸ“¦ Dependencies (Spring Boot 3.x)

Add the following to your pom.xml:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <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>
</dependencies>
Enter fullscreen mode Exit fullscreen mode

πŸ” 1. Basic Authentication for /api/admin/**

Let’s start with securing admin APIs using Basic Auth.

@Configuration
@Order(1)
public class BasicAuthSecurityConfig {

    @Bean
    public SecurityFilterChain basicAuthFilterChain(HttpSecurity http) throws Exception {
        http
            .securityMatcher("/api/admin/**")
            .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
            .httpBasic(Customizer.withDefaults())
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .csrf(csrf -> csrf.disable());

        return http.build();
    }

    @Bean
    public UserDetailsService basicUserDetailsService() {
        UserDetails admin = User.withUsername("admin")
                                .password(passwordEncoder().encode("admin123"))
                                .roles("ADMIN")
                                .build();
        return new InMemoryUserDetailsManager(admin);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ“ Try accessing:

curl -u admin:admin123 http://localhost:8080/api/admin/dashboard


🧾 2. JWT Authentication for /api/user/**

We’ll now secure user APIs using JWTs. First, create a JWT utility class.

πŸ”§ JWT Utility Class

@Component
public class JwtUtils {

    private final String secret = "mysecretkey";

    public String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + 86400000))
                .signWith(Keys.hmacShaKeyFor(secret.getBytes()))
                .compact();
    }

    public String extractUsername(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(secret.getBytes())
                .build()
                .parseClaimsJws(token)
                .getBody()
                .getSubject();
    }

    public boolean validateToken(String token) {
        try {
            extractUsername(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

🧱 JWT Filter

@Component
public class JwtAuthFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private UserDetailsService jwtUserDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        final String authHeader = request.getHeader("Authorization");

        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String jwt = authHeader.substring(7);
            String username = jwtUtils.extractUsername(jwt);

            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                UserDetails userDetails = jwtUserDetailsService.loadUserByUsername(username);

                if (jwtUtils.validateToken(jwt)) {
                    UsernamePasswordAuthenticationToken auth =
                        new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());

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

                    SecurityContextHolder.getContext().setAuthentication(auth);
                }
            }
        }

        filterChain.doFilter(request, response);
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ” JWT Security Configuration

@Configuration
@Order(2)
public class JwtSecurityConfig {

    @Autowired
    private JwtAuthFilter jwtAuthFilter;

    @Bean
    public SecurityFilterChain jwtFilterChain(HttpSecurity http) throws Exception {
        http
            .securityMatcher("/api/user/**")
            .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
            .csrf(csrf -> csrf.disable());

        return http.build();
    }

    @Bean
    public UserDetailsService jwtUserDetailsService() {
        UserDetails user = User.withUsername("john")
                               .password(passwordEncoder().encode("john123"))
                               .roles("USER")
                               .build();
        return new InMemoryUserDetailsManager(user);
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸš€ Testing It Out

πŸ§ͺ Basic Auth

curl -u admin:admin123 http://localhost:8080/api/admin/dashboard
Enter fullscreen mode Exit fullscreen mode

πŸ§ͺ JWT Flow

  1. Simulate login and generate token (you can hardcode for now).
String jwt = jwtUtils.generateToken("john");
Enter fullscreen mode Exit fullscreen mode
  1. Access secure API:
curl -H "Authorization: Bearer <your_token>" http://localhost:8080/api/user/profile
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Final Thoughts

This dual-authentication strategy is incredibly useful when:

  • You need backward compatibility for legacy clients (Basic Auth)
  • You want modern stateless security for SPAs/mobile apps (JWT)
  • You’re building multi-tenant or role-separated services

Spring Security’s filter chains and @Order mechanism make it super easy to support both.

  • Spring Security multiple authentication providers
  • Spring Boot Basic Auth and JWT together
  • Spring Security filter chain for different URL patterns
  • Secure REST API with JWT and Basic Auth
  • Spring Security custom SecurityFilterChain

πŸ™‹ Need Help?

Got stuck? Want the full source code or a GitHub repo? Drop a comment below or message me on LinkedIn!

Until next time, happy coding!

– Your friendly Spring Coach πŸ’»β˜•

Top comments (0)