BFF Proxies for SPAs using Azure API Management

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:

Request flow between SPA, BFF and Authorization Server for retrieving access tokens. Azure API Management implements the flow.

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:

  1. If an access token is present in the cache with the same Session-Token and scope, return it.
  2. If a refresh token is present in the cache with the same Session-Token and scope, request a new access token and return it.
  3. 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.
BFF API configuration in Azure API Management

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.

nielsvanderkaap

nielsvanderkaap

Curious to know more about this topic?

Working at i8c

i8c is a system integrator that strives for an informal atmosphere between its employees, who have an average age of approx 30 years old. We invest a lot of effort in the professional development of each individual, through a direct connection between the consultants and the management (no multiple layers of middle management). 

Quality Assurance

i8c is committed to delivering quality services and providing customer satisfaction. That’s why we invested in the introduction of a Quality Management System, which resulted in our ISO9001:2000 certification. This guarantees that we will meet your expectations, as a reliable, efficient and mature partner for your SOA & integration projects.

i8c - ISO9001-2015

Also worth reading

Exploring the world of IBM: Carlos’ journey to Hursley

In today’s fast-paced digital world, user experience is paramount. One of the common challenges faced by organizations using Azure Active Directory B2C for authentication is the default password reset flow. The process, though functional, lacks personal touch and branding consistency. Frederic, one of our integration experts, created a guide for you on how to implement a custom password reset flow using Azure B2C and Logic App.

Read More »

B2C Custom Password Resets with Logic App

In today’s fast-paced digital world, user experience is paramount. One of the common challenges faced by organizations using Azure Active Directory B2C for authentication is the default password reset flow. The process, though functional, lacks personal touch and branding consistency. Frederic, one of our integration experts, created a guide for you on how to implement a custom password reset flow using Azure B2C and Logic App.

Read More »

Secure a Service Bus Queue Endpoint with Azure API Management

In the context of APIM, the backend service can be a Logic App, Azure Function, or Container App. It can also be a service bus queue or topic or an Event Grid topic. In scenarios to persist a message (request) on a queue or topic for further processing or an event handled further down in a process, APIM can be an option to secure the endpoint of a given Service Bus queue or topic or a customer Event Grid topic.

Read More »