Single Page Applications (SPA) rely on a webpage that is dynamically rewritten by client-side scripting. They deliver a native application experience by providing faster transitions without loading new pages. However, session management with backend REST APIs complicates the implementation and makes them an attractive target for client-side attacks. In order to solve these issues, we implemented a stateful Backend for Frontend (BFF) proxy in Azure API Management (APIM) that uses an OAuth 2.0 authorization server (Azure Active Directory) to authorize requests to backend APIs.
SPAs are an attractive target for client-side attacks
Typically, SPAs interact with the backend data model using REST APIs that are protected with OAuth 2.0 tokens. This introduces several challenges:
- Frontend applications must implement all token retrieval and token refresh operations.
- APIs require public OAuth clients, which enables client impersonation.
- The browser insecurely stores OAuth 2.0 tokens.
- Backend APIs require a properly configured CORS mechanism.
Backend For Frontend (BFF) proxies or the Token Handler Pattern mitigate these issues. Instead of directly connecting to the data model backend, all backend requests run through the BFF proxy. Here, the browser authenticates to the BFF proxy using a session cookie. The session cookie contains the HttpOnly
, MaxAge
, and Secure
attributes. Thisd to make sure that scripts can not extract the session token, to prevent protocol downgrade attacks, and to provide a session timeout mechanism. This mechanism requires the frontend page to be served from the same base domain as the BFF proxy because modern browsers only support first-party cookies.
Stateful vs. Stateless
A BFF proxy can either be implemented stateless or stateful. The stateless variant encrypts tokens and code verifiers and stores these in the session token. This approach reduces storage requirements on the BFF proxy but increases request and response sizes. Furthermore, it requires a rotation policy for encryption keys. Therefore, we implement a stateful BFF proxy in Azure API Management (APIM) that uses an OAuth 2.0 access token to authorize requests to backend APIs. Tokens and verifiers are cached in the proxy, and mapped to a randomized session token. This approach has the following benefits:
- APIM provides a built-in cache store for managing session information.
- APIM can also host the frontend page.
- APIM policies can further tighten security, by setting CSP Headers and CSRF tokens.
- APIM is a scalable service that allows for high throughput.
Implementing the BFF
The BFF proxy acts as a confidential OAuth 2.0 client that is responsible for managing all access tokens. For each inbound request, it translates the session cookie to an OAuth 2.0 access token. Therefore, the proxy requires a client-id
and must implement client authentication. The resulting request flow is shown in the figure below:

First, the proxy exposes an /authorize
endpoint for retrieving authorization codes from the authorization server. This endpoint requires the following OAuth parameters:
scope
response_type
nonce
state
The response forwards the browser to the authorization endpoint using HTTP response code 303 See Other
. Furthermore, it generates a random session token and places it in the Session-Token
cookie. Finally, it adds the client_id
, code_challenge_method
, code_challenge
, and response_mode
OAuth parameters to the redirect URI.
The user must now finish the login process in the browser. After a successful login, the authorization server redirects the browser back to the /authorized?code={authorization-coed}
endpoint. Here, policy expressions retrieve the authorization code, and request the corresponding access_token
and refresh_token
. APIM caches the tokens and redirects the browser back to the SPA, where the cache duration matches the token lifetime. The caching keys contain a combination of the Session-Token
, the scope
, and the type of token. This mechanism permits sessions with multiple access tokens that have a different scope.
After processing the redirect, the SPA performs requests to the backend API through the BFF proxy. Here, the SPA adds the scope
parameter to target the right access token. The BFF proxy resolves the access token using the following decision tree:
- If an access token is present in the cache with the same
Session-Token
andscope
, return it. - If a refresh token is present in the cache with the same
Session-Token
andscope
, request a new access token and return it. - Return an
Unauthorized
exception.
Resulting BFF API
The diagram below shows the resulting structure of the BFF API, which also includes the following endpoints:
/index.html
retrieves the main HTML page, which enables the use of first-party cookies for session management.- /userinfo returns the identity information for the authenticated user.
- /refresh forces a token refresh for all cached tokens for the current session.
- /{resource} represents the actual backend requests, where the BFF API adds the
Authorization
header.

Conclusion
A BFF proxy simplifies the implementation of a SPA and improves its security. APIM is a suitable platform for implementing a BFF:
- It supports policies to implement Access Token and session cookie management.
- It supports internal caching of access tokens and refresh tokens.
- It allows additional logic to be added to API calls, for instance, for implementing CSRF tokens.
- It is a scalable service that supports high throughput.
Policies for the API level and operations level can be found here. An example frontend application is located here. View this post to find out how to monitor the BFF.