Key Principles of modern Authentication in Web Applications

OAuth Standard Flow aka Code Flow

The OAuth 2.0 standard flow, known as the Authorization Code Flow, is a secure protocol designed to enable third-party applications, referred to as clients, to access protected resources on behalf of a user, or resource owner, without exposing the user’s credentials. This flow is ideal for confidential clients, such as web applications with a backend, but is adaptable for public clients like single-page applications through the Proof Key for Code Exchange (PKCE) extension. OAuth defines four key roles: the resource owner, who owns the data; the client, which requests access; the authorization server, such as Keycloak, which authenticates the user and issues tokens; and the resource server, which hosts protected resources and validates access tokens. The flow ensures that the client never handles the user’s login credentials directly, relying instead on redirects and token exchanges to maintain security.

The process starts with the client redirecting the user to the authorization server, where the user authenticates and grants consent. Upon approval, the authorization server redirects back to the client with a short-lived authorization code. The client then exchanges this code for an access token, often a JSON Web Token (JWT), and optionally a refresh token and ID token, through a secure backend channel. The resource server validates the access token to grant access to protected resources. Core principles include using HTTPS for all communications to prevent eavesdropping, employing a state parameter to mitigate cross-site request forgery (CSRF) attacks by correlating requests and responses, and defining scopes to limit access to specific resources. Access tokens are typically short-lived to minimize the risk of compromise, with refresh tokens enabling secure token renewal without requiring re-authentication.

PKCE enhances the security of the Authorization Code Flow for public clients that cannot securely store a client secret. It prevents authorization code interception attacks by introducing a dynamic proof mechanism. The client generates a random, high-entropy code verifier and derives a code challenge from it, typically using the SHA-256 hash function (denoted as S256). The code challenge is included in the initial authorization request. During the token exchange, the client provides the original code verifier, which the authorization server hashes and compares to the stored code challenge. If they match, tokens are issued; otherwise, the request is rejected. This ensures that an attacker intercepting the authorization code cannot redeem it without the verifier, adding robust protection against man-in-the-middle or injection attacks. PKCE is mandatory for native and single-page applications in OAuth 2.1 drafts and is recommended for all clients to enhance security.

Understanding JWT Tokens and Their Validation

JSON Web Tokens (JWTs) are a compact, self-contained mechanism for securely transmitting information between parties as a JSON object, commonly used as access tokens or ID tokens in OAuth 2.0 flows. A JWT consists of three parts: a Header, a Payload, and a Signature, encoded in Base64 and separated by periods (.), forming the structure Header.Payload.Signature. The Header specifies the token type (JWT) and the signing algorithm, such as RS256, which uses RSA with SHA-256 for asymmetric encryption. The Payload contains claims, which are statements about the user or token, such as the issuer (iss), subject (sub), audience (aud), expiration (exp), and issued-at (iat) timestamps, along with custom claims like user roles or permissions. The Signature ensures the token’s integrity by signing the Header and Payload with a private key (for asymmetric algorithms) or a shared secret (for symmetric algorithms like HS256). The resulting token is compact, URL-safe, and can be verified by recipients using the corresponding public key or secret.

In the context of the provided server code, the Express server validates JWTs used as access tokens in the OAuth flow. The validation process begins with extracting the JWT from the Authorization header, expecting the format Bearer <token>. If the header is missing or incorrectly formatted, the server rejects the request with a 401 Unauthorized response. The token is then decoded without verification to inspect its structure, ensuring it contains a valid Header and Payload. The server uses the jwks-rsa library to dynamically fetch the public key from a JSON Web Key Set (JWKS) endpoint, specified as http://localhost:8080/realms/my-realm/protocol/openid-connect/certs in the code. This endpoint, hosted by the authorization server (Keycloak), provides public keys identified by a key ID (kid) in the JWT’s Header. The server verifies the token’s signature using the retrieved public key, ensuring the token hasn’t been tampered with. It also checks critical claims, such as the issuer matching the expected Keycloak realm URL, the token’s expiration to ensure it’s still valid, and the algorithm (RS256) to prevent algorithm downgrade attacks. If any verification step fails—due to an invalid signature, expired token, or mismatched issuer—the server returns a 401 response with detailed error information. Upon successful validation, the decoded claims are attached to the request object, enabling the protected route to access user information, such as roles or identifiers, for authorization decisions. This validation process ensures that only legitimate, unexpired tokens issued by the trusted authorization server can access protected resources, leveraging the JWKS endpoint for scalable and secure key management.

Diagram of Messages Exchanged

The following sequence diagram illustrates the messages exchanged in the OAuth 2.0 Authorization Code Flow with PKCE between the Client (e.g., a React application), the Authorization Server (Keycloak), and the Resource Server (e.g., an Express API). It highlights the authentication process, token exchange (including the issuance of a JWT as the access token), and resource access with JWT validation.

Leave a Reply