Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 61

Stateless Authentication with JWTs

Recommended resources

Welcome to the next lesson! In our previous session, we established a robust system for global exception handling using @ControllerAdvice. This ensures our API responds gracefully and predictably to errors, a key feature of professional-grade applications. Now, with our error handling solidified, we must turn our attention to an even more fundamental aspect of backend development: security.

Currently, our API is completely open. Anyone can create, read, update, or delete employee data without any checks. This lesson will introduce the modern solution to this problem: stateless authentication using JSON Web Tokens (JWT). You will learn what JWTs are, how they work, and why their stateless nature makes them the standard choice for securing modern web applications and microservices. This conceptual understanding is the essential foundation we'll build upon in the next lessons as we implement security in our Spring Boot project.

The Problem: How Does a Server Remember a User?

Before we dive into JWTs, let's consider the fundamental problem. When a user logs in, the server authenticates them. But on their next request, how does the server know it's the same user? HTTP is a stateless protocol, meaning each request is independent.

The traditional solution is stateful session management.

  1. A user logs in.
  2. The server creates a unique session ID, stores it in its memory or a database, and associates it with the user's details.
  3. The server sends this session ID back to the client, usually in a cookie.
  4. The client includes this cookie with every subsequent request.
  5. The server uses the ID to look up the user's session data.

This works, but it has a major drawback in modern architectures: the server must maintain state. This creates scalability challenges. If you have multiple server instances running behind a load balancer, how do you ensure a user's request always goes to the server holding their session? This often requires "sticky sessions" or a centralized session store (like Redis), adding complexity. This is especially problematic in a microservices architecture, where many independent services need to know who the user is.


The Modern Solution: Stateless Authentication with JWT

JSON Web Tokens (JWTs) solve this by moving the state from the server to the client. A JWT is a compact, self-contained token that securely transmits information between parties as a JSON object. "Self-contained" is the key here; the token itself contains all the necessary information about the user, so the server doesn't need to store anything.

The following video gives a fantastic introduction to JWTs, explaining the core concepts and breaking down the token's structure.

JWT Explained In Under 10 Minutes (JSON Web Tokens)

This video from Ariel Weinberger, "JWT Explained In Under 10 Minutes," provides a concise and clear explanation of what JWTs are and why they are so powerful.

First, watch the beginning to solidify your understanding of the difference between authentication and authorization. Authentication is proving who you are; authorization is what you're allowed to do. JWTs are primarily used for authorization. Next, focus on the section explaining the anatomy of a JWT. It consists of three parts separated by dots: header.payload.signature. Finally, pay close attention to the segment on statelessness and encoding. A critical takeaway is that JWT payloads are Base64Url encoded, not encrypted. This means their content is easily readable. You should never store sensitive information like passwords in a JWT payload.

As you saw in the video, a JWT has three parts:

  • Header: Contains metadata about the token, such as the token type (typ, which is "JWT") and the signing algorithm used (alg, e.g., "HS256").
  • Payload: Contains the "claims." These are statements about an entity (typically the user) and additional data. There are standard claims like sub (subject, often the user ID), iss (issuer), and exp (expiration time), as well as custom claims you can add, such as user roles or permissions.
  • Signature: This is the most crucial part for security. It's used to verify that the sender of the JWT is who it says it is and to ensure that the message wasn't changed along the way.

How Verification Ensures Integrity

The signature is what makes a JWT secure. If the payload is just Base64 encoded and readable, what stops a malicious user from decoding it, changing their user ID or adding an "admin": true claim, and re-encoding it? The signature prevents this.

The signature is created by taking the encoded header, the encoded payload, a secret key known only to the server, and hashing them together using the algorithm specified in the header.

Let's see how the server uses this to verify a token on an incoming request.

JWT Explained In Under 10 Minutes (JSON Web Tokens)

The same video explains the signature verification process very clearly.

Watch this short segment to understand how the server verifies the signature. The server re-computes the signature using the header and payload from the token it received, plus its own secret key. If the newly computed signature matches the signature included in the token, the token is valid. If it doesn't match, it means the header or payload was tampered with, and the server rejects the request.

This verification process is the heart of JWT security. Because the client does not know the secret key, it's impossible for them to generate a valid signature for a modified payload.


The Complete JWT Authentication Flow

Now that you understand the components, let's put it all together into the end-to-end authentication flow.

Session Vs JWT: The Differences You May Not Know!

The video "Session Vs JWT" from ByteByteGo provides an excellent animated walkthrough of this entire process.

Watch the segment that illustrates the complete JWT flow. It shows the cycle: User logs in. Server validates and issues a signed JWT. Client stores the JWT. Client sends the JWT in the Authorization: Bearer <token> header on subsequent requests. Server verifies the token and grants access.

This stateless flow is perfect for modern application architectures. In a microservices setup, an authentication service can issue a token, and any other microservice can independently verify it without needing to talk to the authentication service, as long as they have access to the signing key.

Session Vs JWT: The Differences You May Not Know!

As a brief but important aside, there are different ways to sign a token, which affects how services can verify it.

Watch the part explaining signing algorithms. Symmetric (HMAC): The same secret key is used to both sign and verify the token. This is simple and what we will use, but it means any service that verifies tokens must know the secret. Asymmetric (RSA/ECDSA): A private key is used to sign, and a public key is used to verify. This is more secure for distributed systems because you can share the public key widely without compromising the private signing key.


The Security Puzzle: Short-Lived Tokens and Refresh Tokens

There's one big question left: Since JWTs are stateless, the server can't invalidate them. If a token is stolen, it's valid until it expires. If we set a long expiration time (e.g., 30 days) for user convenience, that's a huge security risk.

The industry-standard solution is a two-token strategy: access tokens and refresh tokens.

  • Access Token: This is the JWT we've been discussing. It's sent with every API request. It is very short-lived (e.g., 5-15 minutes). If it's stolen, the window of exposure is small.
  • Refresh Token: This is a second token issued at login. It is long-lived (e.g., days or weeks) and is stored securely by the client. Its only purpose is to get a new access token.

The flow works like this:

  1. The user logs in and receives both a short-lived access token and a long-lived refresh token.
  2. The user makes API calls using the access token.
  3. After 15 minutes, the access token expires. The API returns a 401 Unauthorized error.
  4. The client's front-end code catches this error, and without interrupting the user, silently makes a request to a special /refresh endpoint, sending the long-lived refresh token.
  5. The server validates the refresh token (often by checking it against a list of valid tokens in a database), and if valid, issues a brand new access token.
  6. The client replaces its expired access token with the new one and retries the original failed API call. This all happens seamlessly.

This pattern gives us the best of both worlds: the security of short-lived tokens and the user experience of long-lived sessions.

Session Vs JWT: The Differences You May Not Know!

The ByteByteGo video also covers this essential pattern.

Watch the section that explains the refresh token and access token strategy. It clearly lays out how this two-token approach balances security with usability. For even greater security, systems can implement "refresh token rotation," where a new refresh token is issued every time it's used, invalidating the old one.


Conclusion

You have now learned the fundamental theory behind stateless authentication with JSON Web Tokens. This is a critical concept for any backend developer.

Key Takeaways:

  • Stateless vs. Stateful: JWTs enable stateless authentication, where the server doesn't need to store session data, making applications more scalable.
  • JWT Structure: A JWT consists of a Header, a Payload (with claims), and a Signature. The three parts are Base64Url encoded and separated by dots.
  • Signature is Key: The signature guarantees the token's integrity. It's created with a secret key known only to the server, preventing tampering.
  • Payload is Readable: JWTs are encoded, not encrypted. Never store sensitive data in the payload.
  • Access & Refresh Tokens: The standard security pattern uses short-lived access tokens for API requests and long-lived refresh tokens to obtain new access tokens without forcing the user to log in again.

In our upcoming lessons, we will move from theory to practice. You'll learn how to configure Spring Security, the powerful framework that handles authentication and authorization in Spring Boot applications. We will then proceed to build the endpoints for user registration and login, and finally, generate and validate JWTs to secure our employee management API.