<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/the-backend-for-frontend-bff-pattern-secure-auth-done-right-dh1nx5sor" -->

---
title: The Backend-for-Frontend (BFF) Pattern: Secure Auth Done...
description: The Backend-for-Frontend (BFF) pattern addresses security risks in web applications by storing JWTs server-side in Redis, eliminating exposure to XSS attacks...
canonical: https://daily.dev/posts/the-backend-for-frontend-bff-pattern-secure-auth-done-right-dh1nx5sor
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: The Backend-for-Frontend (BFF) Pattern: Secure Auth Done Right | daily.dev
og:description: The Backend-for-Frontend (BFF) pattern addresses security risks in web applications by storing JWTs server-side in Redis, eliminating exposure to XSS attacks...
og:url: https://daily.dev/posts/the-backend-for-frontend-bff-pattern-secure-auth-done-right-dh1nx5sor
og:image: https://api.daily.dev/og/posts/DH1Nx5Sor.png
og:image:alt: The Backend-for-Frontend (BFF) Pattern: Secure Auth Done Right
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# The Backend-for-Frontend (BFF) Pattern: Secure Auth Done Right

**[WebCraft](https://daily.dev/sources/webcraft)** · [@hamzaidhmad](https://daily.dev/hamzaidhmad) · 3 min read · 258 upvotes · 26 comments

## Summary

The Backend-for-Frontend (BFF) pattern addresses security risks in web applications by storing JWTs server-side in Redis, eliminating exposure to XSS attacks and enhancing session management. This pattern is particularly suited to SPAs and mobile apps, offering improved scalability and user experience with silent token refreshes and instant logouts.

## Content

The Problem with Storing Tokens in localStorage/sessionStorage

Many modern web applications use JSON Web Tokens (JWTs) for authentication, often storing them in localStorage or sessionStorage for easy access. While this approach is simple, it introduces serious security risks:

Vulnerable to XSS Attacks Since localStorage and sessionStorage are accessible via JavaScript, any malicious script running on the page (e.g., from a compromised third-party library or browser extension) can steal tokens. Unlike httpOnly cookies, there’s no built-in protection against token theft via Cross-Site Scripting (XSS).

No Automatic Expiry Management Unlike cookies, which support Max-Age and Expires attributes, localStorage persists until explicitly cleared. If an attacker steals a token, they can use it indefinitely unless the server implements token revocation (which JWTs typically lack).

CSRF Risks When Falling Back to Cookies Some developers try to mitigate XSS by storing JWTs in cookies instead, but this introduces Cross-Site Request Forgery (CSRF) risks unless proper defenses (like SameSite=Strict and CSRF tokens) are implemented.

A Secure Alternative: The BFF (Backend-for-Frontend) Pattern

To avoid these risks, modern applications use a Backend-for-Frontend (BFF) layer combined with server-side token storage (Redis). Here’s how it works:

Tokens Stay on the Server The frontend never sees raw JWTs. Instead, it receives an httpOnly cookie containing only a session ID.
The actual access token and refresh token are stored securely in Redis (or another fast database).

How Authentication Flows Work Login: The BFF validates credentials, generates tokens, stores them in Redis, and sets an httpOnly cookie.
API Requests: The frontend sends the session cookie; the BFF retrieves the access token from Redis and forwards it to APIs.

Token Refresh: When the access token expires, the BFF uses the refresh token (stored in Redis) to get a new one—silently, without user interruption.

Logout: The BFF deletes the Redis entry, invalidating the session.

Why Redis? Speed: Token validation requires sub-millisecond response times (hard to achieve with traditional databases).
Auto-Expiry: Redis supports TTL (Time-To-Live), automatically cleaning up expired sessions.

Revocability: Unlike stateless JWTs, refresh tokens in Redis can be instantly revoked by deletion.

Key Benefits of This Approach ✅ Eliminates XSS Risks Since tokens are never exposed to the frontend, malicious JavaScript can’t steal them.

✅ Better Session Management Short-lived access tokens (15 minutes) minimize damage if leaked.

Long-lived refresh tokens (7 days) provide a seamless user experience.

✅ Scalable & Performant Redis handles millions of token validations per second, making it ideal for high-traffic apps.

The BFF acts as a single point of control, simplifying microservice communication.

When Should You Use This? This pattern is ideal for:

SPAs (React, Angular, Vue) needing secure auth.

Mobile apps where token theft is a concern.

Microservices architectures where APIs shouldn’t handle cookies.

Final Thoughts While localStorage seems convenient, it’s a security anti-pattern for token storage. By moving tokens to a BFF + Redis backend, you get:

Stronger security (XSS/CSRF-resistant).

Better UX (silent refreshes, instant logouts).

Easier scalability (stateless JWTs + Redis performance).

Next Steps:

Implement httpOnly + Secure + SameSite cookies.

Set up Redis with persistence (RDB/AOF) to survive restarts.

Consider token binding (e.g., IP/device fingerprints) for extra security.

## Community discussion

Top comments from developers on daily.dev.

**@michelosaurusrex** · 4 upvotes

> Great explanation, thanks for sharing!

**@eobilas** · 1 upvotes

> Awesome post!!

**@kashyapprajapati** · 1 upvotes

> good one

**@navidgh** · 1 upvotes

> cant the hacker steals the sessID ? i think the main problem still stays there, Am i wrong?

**@haseeb45** · 1 upvotes

> I have recently used this approach in nextjs recently as some of you might know you have to expose your tokens in next-auth if to be used on client side. I made an API route which serves as a proxy between my frontend and backend.

---

Tags: [#security](https://daily.dev/tags/security), [#webdev](https://daily.dev/tags/webdev), [#authentication](https://daily.dev/tags/authentication), [#redis](https://daily.dev/tags/redis)

[View this post on daily.dev](https://daily.dev/posts/the-backend-for-frontend-bff-pattern-secure-auth-done-right-dh1nx5sor)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"DiscussionForumPosting","mainEntityOfPage":"https://daily.dev/posts/the-backend-for-frontend-bff-pattern-secure-auth-done-right-dh1nx5sor","headline":"The Backend-for-Frontend (BFF) Pattern: Secure Auth Done Right","text":"The Backend-for-Frontend (BFF) pattern addresses security risks in web applications by storing JWTs server-side in Redis, eliminating exposure to XSS attacks and enhancing session management. This pattern is particularly suited to SPAs and mobile apps, offering improved scalability and user experience with silent token refreshes and instant logouts.","url":"https://daily.dev/posts/the-backend-for-frontend-bff-pattern-secure-auth-done-right-dh1nx5sor","datePublished":"2025-05-10T18:24:08.127Z","dateModified":"2025-05-10T18:24:20.597Z","author":{"@type":"Person","name":"hamza idhmad","url":"https://daily.dev/hamzaidhmad","image":"https://media.daily.dev/image/upload/s--7glXOfo6--/f_auto/v1746670329/avatars/avatar_7LOXKZEvKwOHcKWOMItM0?_a=BAMClqUq0","interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"EndorseAction"},"userInteractionCount":150}},"image":"https://media.daily.dev/image/upload/s--kDYHiToO--/f_auto/v1746893826/posts/Mw7ChNxlO?_a=BAMClqUq0","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":258},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":26}],"comment":[{"@type":"Comment","text":"Great explanation, thanks for sharing!","datePublished":"2025-05-12T06:34:40.845Z","url":"https://daily.dev/posts/DH1Nx5Sor#c-KFcsh2IYe","author":{"@type":"Person","name":"Michel Van Autrève","url":"https://daily.dev/michelosaurusrex","image":"https://media.daily.dev/image/upload/s--eV5J7frz--/f_auto/v1771493973/avatars/avatar_xtCSMfHED4G2G66vJvJDU?_a=BAMAMiiu0"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":4}},{"@type":"Comment","text":"Awesome post!!","datePublished":"2025-07-28T13:22:41.784Z","url":"https://daily.dev/posts/DH1Nx5Sor#c-zOM6FFcHN","author":{"@type":"Person","name":"Gabriel Nunes","url":"https://daily.dev/eobilas","image":"https://avatars.githubusercontent.com/u/48297244?v=4"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":1}},{"@type":"Comment","text":"good one","datePublished":"2025-07-11T06:34:53.949Z","url":"https://daily.dev/posts/DH1Nx5Sor#c-TDzvRwmdH","author":{"@type":"Person","name":"Kashyap Prajapati","url":"https://daily.dev/kashyapprajapati","image":"https://media.daily.dev/image/upload/s--GR-coqo9--/f_auto/v1748092918/avatars/avatar_ejOLtUi3uMAaN8BrdksTl?_a=BAMClqUq0"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":1}},{"@type":"Comment","text":"cant the hacker steals the sessID ? i think the main problem still stays there, Am i wrong?","datePublished":"2025-06-12T19:08:13.648Z","url":"https://daily.dev/posts/DH1Nx5Sor#c-HzujNL1vr","author":{"@type":"Person","name":"navid gh","url":"https://daily.dev/navidgh","image":"https://lh3.googleusercontent.com/a/ACg8ocKyKdbJ0mn_M8CINSyL5L28q31Jzgrl0kYWks0ufJQkoRB-ig=s96-c"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":1}},{"@type":"Comment","text":"I have recently used this approach in nextjs recently as some of you might know you have to expose your tokens in next-auth if to be used on client side. I made an API route which serves as a proxy between my frontend and backend.","datePublished":"2025-07-15T05:48:36.831Z","url":"https://daily.dev/posts/DH1Nx5Sor#c-QyoK0AMzr","author":{"@type":"Person","name":"Haseeb Ahmed","url":"https://daily.dev/haseeb45","image":"https://lh3.googleusercontent.com/a-/AOh14GgsHYgeAkP6njUnI97Fdkh13mJ3KMxYbhQHiv2w9g=s100"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":1}}],"isPartOf":{"@type":"WebPage","url":"https://daily.dev/squads/webcraft","name":"WebCraft"}}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"WebCraft","item":"https://daily.dev/squads/webcraft"},{"@type":"ListItem","position":3,"name":"The Backend-for-Frontend (BFF) Pattern: Secure Auth Done Right"}]}
```

