By using this site, you agree to the Privacy Policy and Terms of Use.
Accept
World of SoftwareWorld of SoftwareWorld of Software
  • News
  • Software
  • Mobile
  • Computing
  • Gaming
  • Videos
  • More
    • Gadget
    • Web Stories
    • Trending
    • Press Release
Search
  • Privacy
  • Terms
  • Advertise
  • Contact
Copyright © All Rights Reserved. World of Software.
Reading: Securing the Distributed Ecosystem: A Deep Dive into Spring Security and Stateless JWT | HackerNoon
Share
Sign In
Notification Show More
Font ResizerAa
World of SoftwareWorld of Software
Font ResizerAa
  • Software
  • Mobile
  • Computing
  • Gadget
  • Gaming
  • Videos
Search
  • News
  • Software
  • Mobile
  • Computing
  • Gaming
  • Videos
  • More
    • Gadget
    • Web Stories
    • Trending
    • Press Release
Have an existing account? Sign In
Follow US
  • Privacy
  • Terms
  • Advertise
  • Contact
Copyright © All Rights Reserved. World of Software.
World of Software > Computing > Securing the Distributed Ecosystem: A Deep Dive into Spring Security and Stateless JWT | HackerNoon
Computing

Securing the Distributed Ecosystem: A Deep Dive into Spring Security and Stateless JWT | HackerNoon

News Room
Last updated: 2026/02/16 at 8:52 AM
News Room Published 16 February 2026
Share
Securing the Distributed Ecosystem: A Deep Dive into Spring Security and Stateless JWT | HackerNoon
SHARE

Authentication remains one of the most misunderstood and poorly implemented aspectsof modern backend systems. n Not because frameworks are weak — but because security requires correct design decisions, not just dependencies.

In this article, we’ll walk through how to properly secure Spring Boot APIs using Spring Security and JWT, with:

  • Correct password hashing
  • Stateless authentication
  • A custom JWT filter
  • Clean separation of responsibilities
  • Fully working, stable code

1. Why Authentication Still Breaks in Modern Applications

Despite mature frameworks, authentication remains a top attack surface due to:

  • Plain-text or reversible password storage
  • Misunderstanding encryption vs hashing
  • Blind reliance on framework defaults
  • Incorrect JWT usage (tokens without validation)
  • Mixing authentication logic into controllers

Security failures are usually design failures, not tooling failures.

Spring Security is powerful — but only if used intentionally.

2. Encryption vs Hashing: The Most Common Password Mistake

A critical clarification:

| Encryption | Hashing |
|—-|—-|
| Reversible | One-way |
| Requires key | No key |
| Bad for passwords | Correct for passwords |

Why passwords must NOT be encrypted

  • Encrypted passwords can be decrypted
  • Key compromise = full credential leak
  • Violates OWASP recommendations

What secure password storage requires

  • One-way hashing
  • Unique salt
  • Computational cost

Spring Security solves this with BCrypt.

3. Password Hashing That Actually Works (BCrypt)

Configuration

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

Password creation

String hashed = passwordEncoder.encode("password");

Password verification

passwordEncoder.matches(rawPassword, storedHash);
  • Salted
  • Slow by design
  • Resistant to brute force
  • Industry standard

4. JWT: Why Tokens Instead of Sessions?

JWT (JSON Web Tokens) enable stateless authentication.

Session-based authentication

  • The server stores the session
  • Hard to scale
  • Stateful

JWT-based authentication

  • The server does NOT store the session
  • Token is self-contained
  • Horizontally scalable

JWT is not “better” — it’s better for APIs and distributed systems.

5. JWT Token Generation (Core Logic)

JwtService.java

package com.example.jwtdemo.security;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Service;
import java.security.Key;
import java.util.Date;
@Service
public class JwtService {
    private static final String SECRET = "this-is-a-very-secure-secret-key-which-is-at-least-256-bits";
    private static final long EXPIRATION = 1000 * 60 * 60;
    private Key getSignKey() {
        return Keys.hmacShaKeyFor(SECRET.getBytes());
    }
    public String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
                .signWith(getSignKey(), SignatureAlgorithm.HS256)
                .compact();
    }
    public String extractUsername(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(getSignKey())
                .build()
                .parseClaimsJws(token)
                .getBody()
                .getSubject();
    }
}

  • Signed
  • Expiring
  • Tamper-proof
  • Stateless

6. Why You Need a JWT Filter (Most Tutorials Miss This)

Spring Security does NOT automatically validate JWTs.

You must:

  1. Extract token from header
  2. Validate signature
  3. Extract user
  4. Populate Security Context

This must happen before controllers run.

7. JWT Filter Using OncePerRequestFilter

JwtAuthFilter.java

package com.example.jwtdemo.security;
import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
@Component
public class JwtAuthFilter extends OncePerRequestFilter {
    private final JwtService jwtService;
    public JwtAuthFilter(JwtService jwtService) {
        this.jwtService = jwtService;
    }
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) {
        try {
            String authHeader = request.getHeader("Authorization");
            if (authHeader != null && authHeader.startsWith("Bearer ")) {
                String jwt = authHeader.substring(7);
                String username = jwtService.extractUsername(jwt);
                if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                    UsernamePasswordAuthenticationToken authToken =
                            new UsernamePasswordAuthenticationToken(username, null, null);
                    authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(authToken);
                }
            }
            filterChain.doFilter(request, response);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

  • Executes once per reques
  • Stateless
  • Thread-safe
  • Clean separation of concerns

8. Spring Security Configuration (Correct & Minimal)

SecurityConfig.java

package com.example.jwtdemo.config;
import com.example.jwtdemo.security.JwtAuthFilter;
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.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
public class SecurityConfig {
    private final JwtAuthFilter jwtAuthFilter;
    public SecurityConfig(JwtAuthFilter jwtAuthFilter) {
        this.jwtAuthFilter = jwtAuthFilter;
    }
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf(csrf -> csrf.disable())
            .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/auth/**").permitAll()
                .anyRequest().authenticated()
            )
            .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
        return config.getAuthenticationManager();
    }
}

Why this matters

  • CSRF is disabled only because the API is stateless
  • Sessions disabled explicitly
  • JWT filter runs before authentication
  • Public and protected endpoints are clear

9. Login Endpoint with Password Hashing

AuthController.java

package com.example.jwtdemo.controller;
import com.example.jwtdemo.security.JwtService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/auth")
public class AuthController {
    private final JwtService jwtService;
    private final PasswordEncoder passwordEncoder;
    private String storedUser = "admin";
    private String storedPassword;
    public AuthController(JwtService jwtService, PasswordEncoder passwordEncoder) {
        this.jwtService = jwtService;
        this.passwordEncoder = passwordEncoder;
        this.storedPassword = passwordEncoder.encode("password");
    }
    @PostMapping("/login")
    public String login(@RequestParam String username,
                        @RequestParam String password) {
        if (storedUser.equals(username) && passwordEncoder.matches(password, storedPassword)) {
            return jwtService.generateToken(username);
        }
        throw new RuntimeException("Invalid credentials");
    }
}
  • The password is never stored in plain text
  • Token generated only after verification
  • Clean responsibility boundaries

10. Authentication Flow (End-to-End)

Client → POST /auth/login

→ Password verified

*→ JWT generated*

Client → API request

→ Authorization: Bearer <JWT>

→ JwtAuthFilter validates the token

→ SecurityContext populated

→ Controller executes

No session. n No server-side token storage. n Fully stateless. n

11. Login API – Input & Output

Request

POST http://localhost:8080/auth/login?username=admin&password=password

Body

username=admin

password=password

Response (Output)

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTc2OTc2OTMxMSwiZXhwIjoxNzY5NzcyOTExfQ.XbRQxBnuybpyJ7noMOLsg7Z6saeOAwE_D_5nK7ZFnNI

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Twitter Email Print
Share
What do you think?
Love0
Sad0
Happy0
Sleepy0
Angry0
Dead0
Wink0
Previous Article Elon Musk’s X goes down for millions of users worldwide Elon Musk’s X goes down for millions of users worldwide
Next Article Galaxy S26 Ultra selfie camera leak has us playing ‘spot the difference’ Galaxy S26 Ultra selfie camera leak has us playing ‘spot the difference’
Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Stay Connected

248.1k Like
69.1k Follow
134k Pin
54.3k Follow

Latest News

GoveeLife Smart Nugget Ice Maker Pro Review
GoveeLife Smart Nugget Ice Maker Pro Review
Gadget
How Chams, CWG and eTranzact reversed ₦2.4bn in losses
How Chams, CWG and eTranzact reversed ₦2.4bn in losses
Computing
Epic Smartwatch Deal: The Garmin Epix Pro (Gen 2) Is Almost Half for Presidents’ Day
Epic Smartwatch Deal: The Garmin Epix Pro (Gen 2) Is Almost Half for Presidents’ Day
News
Apple May Leave iPad Pro Without Major Upgrades for Years
Apple May Leave iPad Pro Without Major Upgrades for Years
News

You Might also Like

How Chams, CWG and eTranzact reversed ₦2.4bn in losses
Computing

How Chams, CWG and eTranzact reversed ₦2.4bn in losses

14 Min Read
Meet Twilio Segment: HackerNoon Company of the Week | HackerNoon
Computing

Meet Twilio Segment: HackerNoon Company of the Week | HackerNoon

3 Min Read
Linux 6.19.2 & Other LTS Kernels Released To Fix Systems Not Booting
Computing

Linux 6.19.2 & Other LTS Kernels Released To Fix Systems Not Booting

2 Min Read
How to check your UIF status & balance online in 2026
Computing

How to check your UIF status & balance online in 2026

4 Min Read
//

World of Software is your one-stop website for the latest tech news and updates, follow us now to get the news that matters to you.

Quick Link

  • Privacy Policy
  • Terms of use
  • Advertise
  • Contact

Topics

  • Computing
  • Software
  • Press Release
  • Trending

Sign Up for Our Newsletter

Subscribe to our newsletter to get our newest articles instantly!

World of SoftwareWorld of Software
Follow US
Copyright © All Rights Reserved. World of Software.
Welcome Back!

Sign in to your account

Lost your password?