3.6 KiB
PKCE Session Management
PKCESession and pkceSessionMap are uses as part of implementing the Proof Key for Code Exchange (PKCE) flow for OAuth 2.0 authorization with Amazon Cognito.
What PKCE is solving
PKCE extends the OAuth 2.0 authorization code flow to protect against authorization code interception attacks, which is particularly important for public clients (like browser-based apps) that can't securely store a client secret.
Role of PKCESession and pkceSessionMap
The PKCESession and pkceSessionMap together implement a temporary storage mechanism that's critical for the PKCE workflow. Here's why they're necessary:
-
Maintaining state across HTTP requests: OAuth requires multiple HTTP redirects between your application and the identity provider (Cognito in this case). The code needs to remember information from the initial request when the callback happens later.
-
Storing the code verifier: In PKCE, the code verifier is a cryptographically random string generated at the start of the flow, but needed later when exchanging the authorization code for tokens.
The exact flow and how they're used
Let's walk through how they're used in the code:
-
Initial authentication request (
initiateLoginWithPKCEfunction):- Generates a random
stateparameter to prevent CSRF attacks - Generates a random
codeVerifierstring - Creates a
codeChallengeby hashing the verifier using SHA-256 and encoding it - Stores the
codeVerifierin thepkceSessionMapwith thestateas the key - Sends the user to Cognito with the
codeChallengebut NOT thecodeVerifier
- Generates a random
-
Storage phase (
storePKCESessionfunction):- Creates a new
PKCESessionwith thecodeVerifier - Sets an expiration time (5 minutes) to clean up if the flow isn't completed
- Stores it in the in-memory
pkceSessionMapusing thestateas a key - Also performs cleanup of expired sessions
- Creates a new
-
Callback handling (
handleOAuthCallbackfunction):- When Cognito redirects back with the authorization code and state
- Retrieves the previously stored
codeVerifierusing thestateparameter from the query string - Uses
getCodeVerifierfunction to look up the session in thepkceSessionMap - Verifies the session hasn't expired
-
Token exchange (
exchangeCodeForTokensWithPKCEfunction):- Sends the authorization code AND the original code verifier to Cognito
- Cognito verifies that the code verifier, when hashed, matches the code challenge it received earlier
- If valid, Cognito issues the tokens
- The app then validates these tokens and sets them as cookies
Without the PKCESession and pkceSessionMap, the application would have no way to remember the code verifier between the initial request and the callback, making it impossible to complete the PKCE flow.
Security benefits
This approach:
-
Prevents authorization code interception attacks: Even if an attacker intercepts the authorization code, they can't exchange it for tokens without knowing the code verifier, which never leaves your server.
-
Protects against CSRF: The state parameter ensures the callback is responding to a request that your application initiated.
-
Ensures secure token issuance: Cognito will only issue tokens if the code verifier matches the challenge it received earlier.
The implementation in this code uses an in-memory map with locking for thread safety, though as noted in the comments, a production application would likely use a more robust session store (like Redis) especially in a distributed environment.