Files
query-orchestration/cmd/cognito_test/cognito.pkce/cognito_pkce.md
T
2025-04-01 15:34:35 -07:00

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:

  1. 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.

  2. 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:

  1. Initial authentication request (initiateLoginWithPKCE function):

    • Generates a random state parameter to prevent CSRF attacks
    • Generates a random codeVerifier string
    • Creates a codeChallenge by hashing the verifier using SHA-256 and encoding it
    • Stores the codeVerifier in the pkceSessionMap with the state as the key
    • Sends the user to Cognito with the codeChallenge but NOT the codeVerifier
  2. Storage phase (storePKCESession function):

    • Creates a new PKCESession with the codeVerifier
    • Sets an expiration time (5 minutes) to clean up if the flow isn't completed
    • Stores it in the in-memory pkceSessionMap using the state as a key
    • Also performs cleanup of expired sessions
  3. Callback handling (handleOAuthCallback function):

    • When Cognito redirects back with the authorization code and state
    • Retrieves the previously stored codeVerifier using the state parameter from the query string
    • Uses getCodeVerifier function to look up the session in the pkceSessionMap
    • Verifies the session hasn't expired
  4. Token exchange (exchangeCodeForTokensWithPKCE function):

    • 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:

  1. 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.

  2. Protects against CSRF: The state parameter ensures the callback is responding to a request that your application initiated.

  3. 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.