BFF SID Login Logic Modification: A Deep Dive
This article explores the modification of login logic using the Backend For Frontend (BFF) Session ID (SID) method. We'll delve into the intricacies of this approach, its benefits, and how it enhances security and user experience. This guide aims to provide a comprehensive understanding for developers looking to implement or optimize their authentication mechanisms. Let's get started!
๐ Introduction to BFF and SID Login
In modern web development, the BFF pattern is gaining traction as a solution to manage the complexities of front-end applications interacting with multiple back-end services. The BFF acts as an intermediary, tailoring the API to the specific needs of the front-end. This approach simplifies the front-end logic and improves performance.
The Session ID (SID) method, combined with BFF, offers a secure way to manage user sessions. Instead of directly exposing access tokens or refresh tokens to the browser, the BFF manages these tokens server-side and issues a session ID to the browser. This session ID is then used for subsequent requests, adding an extra layer of security. This method significantly reduces the risk of token theft and Cross-Site Scripting (XSS) attacks.
The BFF pattern provides a clear separation of concerns, allowing front-end and back-end teams to work independently. It also improves the overall architecture by reducing the complexity of the front-end and providing a more streamlined API. Using SID in conjunction with BFF further enhances the security posture of the application by keeping sensitive tokens server-side.
By adopting this approach, developers can build more secure, scalable, and maintainable web applications. The combination of BFF and SID provides a robust framework for managing user authentication and authorization in complex systems.
๐ Current Challenges with Traditional Token Management
Traditionally, web applications managed user authentication by storing access tokens and refresh tokens directly in the browser, often using local storage or cookies. While this approach is straightforward, it introduces significant security vulnerabilities. Storing tokens in the browser makes them susceptible to Cross-Site Scripting (XSS) attacks, where malicious scripts can access and steal these tokens, compromising user accounts.
Another challenge with client-side token management is the increased risk of Cross-Site Request Forgery (CSRF) attacks. Although modern frameworks provide some protection against CSRF, the risk is still present. By contrast, The BFF pattern, combined with the SID method, mitigates these risks by keeping tokens server-side.
Managing token expiration and renewal in the browser can also be complex. Developers need to implement logic to refresh tokens before they expire, which adds complexity to the front-end code. With the BFF pattern, token refresh logic is handled server-side, simplifying the front-end development process.
The traditional approach also makes it harder to implement advanced security measures such as token rotation and revocation. These measures are crucial for maintaining a robust security posture, but they are difficult to implement when tokens are stored in the browser. Server-side token management, as facilitated by the BFF pattern, makes it easier to implement these advanced security features.
Therefore, transitioning to a BFF architecture with SID-based authentication offers a more secure and manageable approach to user authentication. This method reduces the attack surface and simplifies the implementation of security best practices.
๐ ๏ธ Proposed Solution: BFF with Session ID (SID)
The proposed solution involves leveraging the BFF pattern in conjunction with Session IDs (SIDs) to manage user authentication. This approach shifts the responsibility of handling access tokens and refresh tokens from the browser to the front-end server (BFF), enhancing security and simplifying the front-end logic. The core idea is that the browser only interacts with a session ID, while the BFF securely manages the actual tokens.
The architecture can be visualized as follows: Browser โ Front-end Server (Next.js BFF) โ Back-end API (Spring Boot). The key to this pattern is defining how access tokens and refresh tokens are transferred between the browser and the front-end server, and between the front-end server and the back-end API.
0. Defining the Pattern (Recommended)
The recommended pattern for BFF architecture emphasizes server-to-server token exchange and issues a session ID (SID) to the browser. This means that tokens are only exchanged between the BFF and the back-end, while the browser receives a session cookie, a randomly generated ID. Specifically, tokens are stored in a server-side repository (such as memory or Redis), and the browser receives an HttpOnly cookie containing only the sessionId. When a protected resource request is sent, the browser transmits only the sessionId cookie to the BFF, which then communicates with the back-end using the appropriate access token.
This pattern aligns with current security best practices for BFF + OAuth/JWT architectures and offers the highest level of security. Therefore, the following sections will primarily describe the process based on this architecture. Later in the article, we will briefly discuss alternative approaches where tokens are placed directly in the browser's HttpOnly cookies.
1. Browser โ Front-end Server (BFF) Section
This section describes how the browser communicates with the front-end server (BFF) using session cookies instead of tokens.
1-1. Login Scenario
- Browser โ Front-end Server
- The browser sends a POST request to the login endpoint (e.g.,
POST https://www.domain.com/api/auth/login). - The request body contains user credentials in JSON format, such as email and password.
- At this stage, there are no tokens or cookies involved.
- The browser sends a POST request to the login endpoint (e.g.,
- Front-end Server Internal Processing
- The front-end server communicates with the back-end API to authenticate the user and retrieve
accessTokenandrefreshToken. - The BFF generates a random
sessionId(e.g.,sid_9fd7a...).
- The front-end server communicates with the back-end API to authenticate the user and retrieve
- Front-end Server โ Browser Response
- The front-end server sends a response to the browser with a
Set-Cookieheader, containing only the session cookie. - The cookie is configured as
HttpOnly,Secure,SameSite=Strict, andPath=/. - The response body contains user information (e.g., ID, name, role) but does not include access tokens or refresh tokens.
- The key point here is that the access token and refresh token strings never reach the browser; the browser only receives a session cookie.
- The front-end server sends a response to the browser with a
1-2. General API Call
- Browser โ Front-end Server
- When the browser makes a request to a protected resource (e.g.,
GET https://www.domain.com/api/tickets), - It automatically attaches the session cookie in the request header (
Cookie: sid=SID_random_value). - The request does not include the
Authorizationheader since the browser is unaware of the tokens.
- When the browser makes a request to a protected resource (e.g.,
- Front-end Server Internal Processing
- The front-end server uses the
sidfrom the cookie to query the session store (e.g., Redis, database). - The session store contains the
accessTokenandrefreshTokenassociated with thesessionId.
- The front-end server uses the
- This process then flows into the communication between the front-end server and the back-end, which we'll describe later.
1-3. Access Token Expiration โ Refresh
- The browser continues to send requests with only the
sidcookie. - If the BFF detects that the access token has expired, it initiates a token refresh process with the back-end API.
- During this process, the exchange of token bytes remains confined between the BFF and the back-end, and the browser remains isolated from these details.
2. Front-end Server (BFF) โ Back-end API Section
This section details the direct exchange of accessToken and refreshToken between the BFF and back-end API.
2-1. Login Phase (Initial Token Issuance)
-
Front-end Server โ Back-end
- The front-end server sends a POST request to the authentication endpoint of the back-end API (e.g.,
POST https://api.domain.com/auth/login). - The request includes the user's credentials (e.g., email, password) in the JSON body.
- The front-end server sends a POST request to the authentication endpoint of the back-end API (e.g.,
-
Back-end โ Front-end Server Response
- A common pattern (similar to Auth0) involves responding with access and refresh tokens in the JSON body:
{ "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI...", "refreshToken": "def50200b9c1c...", "accessTokenExpiresIn": 900, "refreshTokenExpiresIn": 1209600 }- It's recommended to transmit both tokens in the JSON body, as this is server-to-server communication, so there are fewer concerns about CORS and cookies.
-
Front-end Server Internal Processing
- The front-end server generates a
sessionId. - The server stores the
{ accessToken, refreshToken, userInfo }tuple in a server-side repository (such as Redis) using thesessionIdas the key. - Finally, the server transmits the
sidcookie to the browser, as described in Section 1.
Summary
- In the login response,
accessToken/refreshTokenshould be transmitted only in the JSON body to the BFF.- The browser receives only the session cookie.
- The front-end server generates a
2-2. Protected API Request Phase (Using Access Token)
Now, let's examine a scenario where the browser is retrieving some data:
-
Example of Request Received by the Front-end Server
- Browser:
GET /api/tickets+Cookie: sid=... - The front-end server retrieves the
accessTokenby querying the session store using thesid.
- Browser:
-
Front-end Server โ Back-end API Call
- Example:
GET https://api.domain.com/tickets - The request includes the
Authorizationheader using the standard bearer token format:
GET /tickets HTTP/1.1 Host: api.domain.com Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI...- Most JWT/OAuth documentation explicitly states that access tokens should be transmitted via the
Authorization: Bearerheader.
- Example:
-
Back-end โ Front-end Server
- After verifying permissions, the back-end responds with JSON data:
[ { "id": 1, "title": "..." }, { "id": 2, "title": "..." } ] -
Front-end Server โ Browser
- This JSON response is transmitted (or transformed) to the browser.
- The browser still remains unaware of the tokens.
Summary
- In the front-end server โ back-end section, the access token is always transmitted only in the Authorization header (
Bearer <token>).
2-3. Using Refresh Tokens (Reissuing Access Tokens)
When the access token expires, the BFF should automatically initiate a refresh request.
-
BFF Detects 401/Expiration during API Call
- If an API request (such as
/tickets) returns a 401 error, it indicates that theaccessTokenhas expired.
- If an API request (such as
-
Front-end Server โ Back-end Token Reissuance Request
There are two main ways to transmit the refresh token here:
(A) Transmitting in JSON Body (Common Pattern)
POST /auth/refresh HTTP/1.1 Host: api.domain.com Content-Type: application/json { "refreshToken": "def50200b9c1c..." }- Advantages:
- Clear and easily distinguishable for logging purposes.
- Avoids mixing roles with the
Authorizationheader (access =Authorization, refresh = body).
(B) Transmitting via
AuthorizationHeaderPOST /auth/refresh HTTP/1.1 Host: api.domain.com Authorization: Bearer def50200b9c1c...- Advantages:
- Consistency in the
- Advantages: