Phase 3: Authentication & Security

Token revocation, session hijacking prevention & SSO

Intermediate ~3 min read
Think of it this way A friendly analogy. Read this if the technical version feels dense. Show Hide

Imagine you're at a super fun amusement park! To get on the best rides, you need a special wristband. This wristband shows everyone that you paid and are allowed to be there. In the world of computers, when you log into a website or app, it's like getting one of these wristbands, but we call it a "token." It's your digital pass that says, "Hey, this is me, and I'm allowed to see my profile or play my game!"

Now, what if you lose your wristband, or someone sneaky tries to grab it from you? That would be a problem! If someone else found your wristband, they could pretend to be you and get on all your favorite rides. To stop this, the park needs a way to "cancel" your wristband if it gets lost or stolen. For some simple passes, like a ride ticket, the park attendant might just tear it up when you use it. But for a fancy wristband that doesn't get "torn," the park has a special "Uh-Oh List." Every wristband has a unique number, and if your wristband's number gets added to the Uh-Oh List because it was lost or stolen, then even if someone tries to use it, the attendant will check the list and say, "Nope! That wristband isn't valid anymore."

The sneaky person using your lost wristband is a bit like "session hijacking" in the computer world. It's when an attacker gets hold of your digital pass (your token) and uses it to pretend they are you, getting into your account and seeing your private stuff. By having that "Uh-Oh List" (which is sometimes called a "blocklist"), even if a hacker steals your digital wristband, you can tell the system to quickly put that wristband's unique number on the list. Then, the hacker's stolen pass won't work anymore, and they can't get into your account.

So, when you build your own games or websites someday, knowing about these digital wristbands and how to put them on an "Uh-Oh List" means you can make sure your users' accounts stay super safe. If someone changes their password, logs out, or loses their phone, you can instantly make sure their old digital passes don't work anymore, protecting their secret online treehouse from any digital pranksters!

When dealing with authentication tokens, especially long-lived ones, the ability to revoke them is critical for security and user experience. For server-side sessions, revocation is straightforward: simply delete the session data stored on your backend. When a user logs out, changes their password, or a session is deemed compromised, destroying this data invalidates their current session. With stateless JWTs, revocation is trickier because the token itself contains all necessary information and isn't inherently tied to server-side state. To "revoke" a JWT before its natural expiry, you typically implement a server-side "blocklist" (also known as a blacklist). When a JWT needs to be invalidated (e.g., user logout, token compromise), its unique identifier (jti) is added to this blocklist. Every incoming JWT is then checked against this list; if its jti is present, the token is rejected. This blocklist needs to be persisted and quickly accessible, often utilizing a fast key-value store like Redis.

Session hijacking occurs when an attacker obtains a legitimate user's session token (often a cookie) and uses it to impersonate the user, gaining unauthorized access to their account. Preventing this relies on multiple layers of defense. First, always serve your application over HTTPS/TLS to encrypt traffic and prevent eavesdropping on session tokens. Second, configure your session cookies with critical flags: HttpOnly prevents client-side JavaScript from accessing the cookie, mitigating XSS attacks; Secure ensures the cookie is only sent over HTTPS; and SameSite=Lax or Strict protects against CSRF (Cross-Site Request Forgery) attacks by restricting when cookies are sent with cross-site requests. Additionally, implement mechanisms like short session expiry times, regularly regenerating session IDs, and potentially tying sessions to user-agent strings or IP addresses (though be cautious with dynamic IPs, like mobile networks, to avoid false positives).

Single Sign-On (SSO) dramatically improves user experience and simplifies identity management by allowing users to log in once to a central identity provider and then gain access to multiple independent applications without re-entering their credentials. Instead of each application managing its own authentication, they delegate this responsibility to the IdP. Common protocols enabling SSO include OAuth2 (primarily for authorization delegation) and OpenID Connect (OIDC), which builds on OAuth2 to add an identity layer. From a backend perspective, implementing SSO often means integrating your application as a "Service Provider" (SP) that trusts the "Identity Provider" (IdP) to authenticate users and provide verifiable identity tokens or assertions. This centralizes security policy enforcement, reduces password fatigue for users, and streamlines account provisioning and de-provisioning.

Key Takeaways

  • JWT revocation uses a server-side blocklist (e.g., in Redis) of jtis, while session revocation is simply destroying server-side session data.
  • Prevent session hijacking by securing cookies with HttpOnly, Secure, SameSite flags and always using HTTPS/TLS.
  • SSO enhances UX and centralizes identity management by letting users log in once to an Identity Provider for access to multiple applications, often using OAuth2/OpenID Connect.

Code Example

python
blocked_jwt_ids = set() # In a real app, this would be a persistent store like Redis

def revoke_jwt(jwt_id: str):
    """Adds a JWT ID to the blocklist to invalidate it."""
    blocked_jwt_ids.add(jwt_id)
    print(f"JWT ID {jwt_id} has been blocked.")

def is_jwt_blocked(jwt_id: str) -> bool:
    """Checks if a JWT ID is currently in the blocklist."""
    return jwt_id in blocked_jwt_ids

# Example Usage within your token validation middleware:
# if is_jwt_blocked(decoded_jwt_payload.get('jti')):
#     raise UnauthorizedError('Token revoked')

How this code works

This code establishes a fundamental way to revoke JSON Web Tokens (JWTs) after they've been issued, which is vital for preventing session hijacking and maintaining security. When a user logs out, changes their password, or a token is suspected of being compromised, it needs to be invalidated immediately, rather than waiting for its natural expiration. The code provides a mechanism to explicitly block specific tokens, ensuring they can no longer grant access to the system.

At its core, the system uses blocked_jwt_ids, a Python set, to store the unique identifier (jwt_id, often called jti) of each token that has been revoked. The revoke_jwt function simply adds a jwt_id to this set, marking it as invalid. Conversely, the is_jwt_blocked function quickly checks if a given jwt_id exists in blocked_jwt_ids. A subtle but crucial detail is that blocked_jwt_ids is an in-memory set; in a production application, this blocklist would need to be stored in a persistent database like Redis, as suggested by the comment, so that revoking a token remains effective even if the server restarts. The example usage illustrates how is_jwt_blocked would be integrated into a server's token validation process, rejecting any requests made with a revoked jti.