BFF Pattern for Secure Authentication

Neelesh RoyNeelesh Roy
4 min read

TL;DR:

Storing tokens in localStorage or sessionStorage exposes your app to XSS and CSRF vulnerabilities. A better approach? Use a Backend-for-Frontend (BFF) with server-side token storage (like Redis) and httpOnly cookies. Secure by design. Scalable by default.

The Problem with Storing JWTs in localStorage/sessionStorage

Modern SPAs (React, Angular, Vue) often use JSON Web Tokens (JWTs) for authentication. The most common pattern?

// Login
localStorage.setItem('access_token', 'eyJhbGciOi...');
// Fetching APIs
fetch('/api/user', {
  headers: {
    Authorization: `Bearer ${localStorage.getItem('access_token')}`
  }
});

While this looks simple and works great for demo apps, it comes with critical security flaws in production.

  • Vulnerable to XSS
    Any JavaScript running on your site—including malicious scripts from a compromised package, CDN, or browser extension—can read from localStorage or sessionStorage. That means your tokens are one XSS attack away from being stolen.

  • No Built-in Expiry Management
    Unlike cookies, localStorage does not auto-expire. If a token is leaked, it stays valid until:

    • You explicitly remove it from localStorage

    • It naturally expires (e.g. 1-hour token)

    • Your backend implements some manual revocation logic (rare with stateless JWTs)

That's a huge window of opportunity for attackers.

  • CSRF Comes Back if You Use Cookies Poorly
    Some devs move JWTs into cookies to protect against XSS — good move. But if you're not careful, you're now exposed to Cross-Site Request Forgery (CSRF).

Enter BFF - A Better Pattern

Instead of shipping tokens to the browser, you:

  • Store them securely on the server (e.g., Redis)

  • Use a lightweight, httpOnly session cookie to identify the user

How the BFF Auth Flow Works

The Backend-for-Frontend (BFF) pattern fixes these issues by never exposing tokens to the frontend.

Here's the step-by-step breakdown:

  1. Login

    • User submits credentials to the BFF.

    • BFF verifies credentials, generates access & refresh tokens.

    • Stores both in Redis.

    • Sends back a signed httpOnly, Secure, SameSite=Strict cookie with just a session ID.

  2. API Requests

    • The browser sends the cookie automatically with each request.

    • The BFF reads the session ID, fetches tokens from Redis.

    • It uses the access token to call downstream APIs or services.

  3. Token Refresh

    • When the access token expires (e.g., after 15 minutes), the BFF uses the refresh token (stored in Redis) to obtain a new access token.

    • The user experiences no downtime or login prompts.

  4. Logout

    • Session is deleted from Redis.

    • Cookies are cleared.

    • User is instantly logged out on all devices.

Why Redis?

Redis is tailor-made for this setup.

  • Blazing Fast: Token lookups happen in sub-millisecond time.

  • Auto-Expiry (TTL): Redis handles token expiration automatically. No manual cleanup required.

  • Revocability: You can instantly kill sessions by deleting the key.

  • Resilience: With AOF/RDB, sessions persist across restarts.

Key Security Advantages

  1. Eliminates XSS Attack Surface
    No tokens ever touch the browser. Even if your JS is compromised, your tokens are safe.

  2. Robust Session Management
    Short-lived access tokens (15 mins) for minimal damage if leaked

    Long-lived refresh tokens (7 days) for better UX

    No race conditions or juggling between tokens on the client

  3. Built for Scale
    Redis can handle millions of token operations per second.

    The BFF becomes a single point of control and abstraction, simplifying your microservice interactions.

  4. Instant Logout & Token Revocation
    Unlike stateless JWTs, which can’t be revoked once issued, Redis-stored tokens can be nuked in a single command.

The BFF + Redis approach is a great fit if you're building:

  • A Single Page Application (SPA) using React, Angular, or Vue

  • A mobile app with concerns around token leakage

  • A microservices backend, where each API shouldn't handle session cookies directly

  • A zero-trust environment, where you want the most control over session lifecycle

Final Thoughts

Storing JWTs in localStorage may be convenient, but it's a security anti-pattern. It opens you up to XSS and provides no reliable way to revoke tokens.

By moving token management server-side with a BFF and Redis, you get:

  • Stronger security (XSS/CSRF-proof)

  • Smoother UX (silent refresh, reliable logout)

  • Better scalability (stateless API, centralized auth)

In today's threat landscape, security should be the default, not an afterthought. BFF is the path forward.

0
Subscribe to my newsletter

Read articles from Neelesh Roy directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Neelesh Roy
Neelesh Roy

Neelesh is a Senior Frontend Engineer in the insurance technology industry. He specializes in building responsive, reliable, and user-friendly web applications. With years of experience in modern JavaScript frameworks, he cares deeply about clean code, performance, and good user experience. Neelesh enjoys solving complex business problems with simple, practical solutions. He often works closely with designers and backend teams to bring ideas to life. Outside of work, he likes to stay updated with the latest in web development and technology trends.