Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Token Caching and Session Replication for HA Identity Systems

Hello! Welcome back to our journey into architecting security products.

In our last lesson, we designed a low-latency policy evaluation engine, diving deep into the caching and distribution strategies that make systems like Google Zanzibar perform at a global scale. We now have a clear blueprint for how an identity system makes authorization decisions. However, a decision is useless without context, and in identity, that context is the user's authenticated session.

This brings us to our learning outcome for today: Design token caching and session replication strategies for a highly available, distributed identity system.

We'll explore how to manage a user's session once they are authenticated, ensuring that the system is resilient to failures and performs well across multiple data centers. This is a classic distributed systems design problem, where the principles of high availability, data replication, and caching are paramount.

1. The Core Trade-off: Stateless vs. Stateful Sessions

The first architectural decision in session management is whether to store session state on the server or to entrust it to the client.

  • Stateless Sessions (e.g., JSON Web Tokens - JWTs): In this model, all necessary session data (user ID, roles, etc.) is packed into a token, digitally signed by the server, and sent to the client. The client includes this token with every subsequent request.

    • Pros: Highly scalable, as any server with the signing key can validate the token without needing a central session store. This fits naturally into distributed, microservices-based architectures.
    • Cons: The main drawback is revocation. If a token is compromised, it remains valid until its expiration time. You cannot easily "kill" a stateless token.
  • Stateful Sessions (e.g., Session IDs): The server creates a session, stores the session data in a central datastore, and gives the client a simple, random string—the session ID. The client sends this ID with each request, and the server uses it to look up the full session details.

    • Pros: Sessions can be revoked instantly by deleting the record from the server's datastore. This provides much greater control and security.
    • Cons: It requires a fast, scalable, and highly available session store. This store can become a performance bottleneck and a single point of failure if not designed correctly.

Let's explore this trade-off further with a resource that discusses it in the context of identity system continuity.

Identity Continuity and Failover Automation

This article from the Identity Management Institute directly contrasts stateless and stateful approaches for ensuring session continuity.

Please read the section titled 'Session Persistence & Failover Protocols'. Focus on how it describes the resilience of stateless JWTs versus the requirements for stateful sessions using an 'in-memory distributed data grid'.

As the article notes, while JWTs offer inherent resilience, the need for immediate revocation in many high-security scenarios pushes us toward stateful sessions. For instance, if an administrator needs to immediately terminate a user's access across all applications, a stateful system is far more effective.

Global Token Revocation and Backchannel Logout Sequence Diagram
This diagram illustrates a federated logout process. A central identity provider, upon revoking a user's session, can send 'backchannel logout' requests to all connected applications. This is only possible if the IdP maintains a stateful record of the user's active sessions.

The challenge, then, becomes building a stateful session store that doesn't compromise on availability or performance.

2. Architecting a Highly Available Session Store

To build a stateful system that can scale and survive failures, we need to move from a single session database to a distributed session store. This is essentially a specialized, low-latency, distributed key-value store where the key is the session ID and the value is the session object.

Session Storage Architecture with Redis
This diagram shows a common architecture where application APIs (like an Account Dashboard) rely on a dedicated, centralized Session Store (here, using Redis) to manage user sessions, decoupling it from the application logic and the core Identity Provider (IDP).

One of the most common technologies for this purpose is Redis. Given your interest in first-principles understanding, let's dive into how Redis works and how its features enable the creation of a distributed session store.

Redis Deep Dive w/ a Ex-Meta Senior Manager

This video gives a great deep dive into Redis, covering its fundamental design, replication for high availability, and sharding for scaling. This will provide the foundational knowledge for our session store design.

Please watch the following three segments: Redis Fundamentals (02:10 - 05:33): Understand why its single-threaded, in-memory nature makes it so fast. Multi-Node Environments (05:39 - 09:54): Pay close attention to how replication provides read scaling and failover, and how sharding (keyspace/slots) provides write scaling. Redis as a Cache (09:54 - 12:44): Focus on expiration policies like Time-to-Live (TTL), which are crucial for session management.

The video highlights the core building blocks Redis provides:

  • In-memory speed: Perfect for low-latency session lookups.
  • Replication (Primary-Replica): Allows for failover and scaling read traffic.
  • Sharding (Redis Cluster): Distributes the data (and write load) across multiple primary nodes, enabling horizontal scaling.

Now, let's zoom out from the specific technology and look at the high-level architectural patterns for replicating data across regions.

3. Multi-Region Replication Patterns

For a truly global identity system that can survive a regional outage, we need to replicate session data across different geographic regions. The choice of replication strategy involves significant trade-offs.

High Availability Architectures PART 2 - Datastores - Multi-Region HA DB architecture

This video explains the core architectural patterns for building highly available, multi-region data stores. These concepts apply directly to our distributed session store.

Please watch these sections to understand the key patterns and trade-offs: Why multi-region? (01:32 - 04:43): Covers the motivation for performance and failover. Consistency (04:43 - 07:08): A crucial primer on consistency and unavoidable replication lag. Read Replicas (12:05 - 16:41): This is the Active-Passive pattern. Promoting a Replica (16:41 - 19:49): Explains the failover process in an Active-Passive setup. Multi-Primary with Sharding (19:49 - 24:39): This is the Active-Active pattern.

Let's synthesize these patterns in the context of our session store:

Active-Passive (Primary with Read Replicas)

  • Architecture: One region hosts the primary session store that accepts all writes (new sessions, session updates). Other regions have read-only replicas that receive data via asynchronous replication.
  • Use Case: Good for when you have a primary user region, and other regions are for disaster recovery or have read-heavy workloads.
  • Pros: Simpler to reason about consistency, as there's a single source of truth for writes.
  • Cons:
    • Writes from non-primary regions incur high latency.
    • Failover requires a "promotion" event, which involves downtime and potential data loss if the replication lag hasn't caught up.

Active-Active (Multi-Primary)

  • Architecture: Multiple regions host primary session stores, each accepting read and write traffic. Data is replicated bi-directionally between them.
  • Use Case: Ideal for global applications where users are distributed and need low-latency reads and writes from their local region.
  • Pros: Excellent performance and seamless failover. If one region goes down, the others continue operating without interruption.
  • Cons:
    • Complexity. This is much harder to manage. The biggest problem is write conflicts. What happens if a user's session is modified in two regions at the same time?
    • To mitigate conflicts, you can use a sharding strategy. For example, you can hash the user_id to assign a "home" region to each user's session. All writes for that session are routed to its home region, while other regions hold replicas. This turns it into a set of distributed Active-Passive systems, avoiding conflicts while maintaining low read latency everywhere.

As you can see, the core challenge is balancing consistency, availability, and latency, a familiar problem from your distributed systems background.

4. Token Caching Strategies

Separate from managing the stateful session on the IdP side, we also need to consider caching on the client-side of the IdP: the resource servers (APIs) and API gateways that consume tokens. Caching here is critical to prevent the IdP from becoming a bottleneck.

There are two main types of tokens to consider caching for:

  1. JWT Validation: When a resource server receives a JWT, it must validate its signature. To do this, it needs the IdP's public signing key, typically fetched from a /.well-known/jwks.json endpoint. These keys rotate infrequently. The resource server must cache the JWKS response to avoid a network call to the IdP on every single request. A simple in-memory cache with a TTL (e.g., a few hours) is sufficient.

  2. Opaque Token Introspection: Some systems use opaque tokens (or reference tokens)—short, random strings that are not self-contained JWTs. To get the user information associated with an opaque token, the resource server must call the IdP's /introspect endpoint.

    • Making this network call on every API request is too slow.
    • The solution is to cache the introspection response. The resource server can use a distributed cache (like Redis, as we saw in the video) to store the introspection result, using the opaque token itself as the cache key.
    • This cache should have a very short TTL (e.g., a few seconds to a few minutes) to balance performance with the risk of using stale data. This effectively turns a high-latency introspection call into a low-latency cache lookup for the lifetime of the cache entry.

5. Advanced Strategy: Session-Aware Reconciliation

For a deeper look, let's explore a more advanced concept from academic research that optimizes how session data is replicated.

[PDF] SessionStore: A Session-Aware Datastore for the Edge

The 'SessionStore' paper proposes a clever way to handle session consistency for mobile users at the network edge. Its design considerations are highly relevant for any globally distributed system.

This is a deeper dive, so focus on the high-level concepts rather than the implementation details. Read Section IV, 'DESIGN CONSIDERATIONS': This section frames the design space perfectly, discussing the trade-offs between proactive vs. reactive synchronization and full vs. session-aware reconciliation. Skim Section V, 'SESSIONSTORE': Focus on the basic idea. The system tracks the data a session reads or writes. When a user switches to a new replica (data center), instead of syncing everything, it only syncs the data relevant to that specific session.

The key idea from SessionStore is that when a user session moves from one data center to another, you don't need to replicate the entire session database. You only need to ensure that the data that particular session has seen or modified is consistent at the new location. This session-aware reconciliation is a powerful optimization that minimizes data transfer and latency, making it highly suitable for large-scale, geo-distributed identity systems.

Conclusion

In this lesson, we designed the strategies for managing sessions and tokens in a highly available distributed identity system. We saw that this is fundamentally a distributed data management problem with clear trade-offs.

Key Takeaways:

  • Stateless vs. Stateful: The initial design choice is between stateless JWTs (scalable, hard to revoke) and stateful session IDs (revocable, but require a highly available session store).
  • Distributed Session Store: For stateful sessions, a distributed in-memory key-value store like Redis is a common choice, providing the building blocks for replication and sharding.
  • Replication Patterns: Active-Passive architectures are simpler but have higher failover latency, while Active-Active architectures offer better performance and availability at the cost of higher complexity, especially regarding write conflicts.
  • Token Caching: At the resource server, caching is non-negotiable. This includes caching public keys (JWKS) for JWT validation and caching the results of opaque token introspection.
  • Session-Aware Reconciliation: Advanced systems can optimize replication by only synchronizing the data relevant to a specific session when it moves between data centers, saving bandwidth and time.

Preview of the Next Lesson:

Now that we've architected how to maintain a secure and available session, our next lesson will focus on a standard protocol for communicating identity information. We will address the outcome: "Design the OIDC layer on top of OAuth 2.0, including ID token generation, claims management, and the UserInfo endpoint." We'll see how the famous ID Token, a specific type of JWT, is constructed and used to deliver user identity claims to applications in a secure, standardized way.

Can't find a good explanation? Sign up and we'll make it for you

Sign up