advanced 3 min answer

A single-page app has used the OAuth implicit flow since 2017 and keeps the access token in localStorage. Security wants authorization code with PKCE behind a backend-for-frontend holding a cookie session. 180000 daily users and 40 third-party embeds must not be logged out. Sequence the migration.

oauthpkcebackend-for-frontendmigrationcsrf
Show the full answer Hide the answer

What is being tested

Whether you can change an authentication mechanism under live traffic, and whether you notice that this migration adds a vulnerability class while removing another. Moving the credential from a header to a cookie removes cross-site scripting token theft and introduces cross-site request forgery. A plan that does not name CSRF defence is incomplete.

The sequence

  1. Register a second client at the identity provider for the code-plus-PKCE flow. The old implicit client stays live and untouched. Nothing is reversible after this point if you edit the existing client in place.
  2. Stand up the BFF token endpoint. It performs the code exchange server-side, keeps the access and refresh tokens in server-side session state, and sets one cookie: HttpOnly, Secure, SameSite=Lax, host-scoped. Add a CSRF defence in the same change, not later: either the double-submit token or an Origin check on every state-changing method.
  3. Make the resource servers dual-accept for a bounded window: a bearer token in the header, or a BFF-minted session. Instrument which path each request used. You cannot ramp without this counter.
  4. Flag 1% of users onto the new flow. Watch the 401 rate, the refresh rate and the session-length distribution rather than overall errors, because a broken refresh shows up as users silently re-logging in.
  5. Ramp to 100% over two weeks, keeping the flag per-user and sticky so a user does not flip mid-session.
  6. Disable the implicit grant on the old client, then delete the localStorage key on next page load.

Where data can diverge

A user with two tabs on two app versions holds two credentials: a localStorage token in one, a cookie session in the other. Logging out in one tab does not end the other session, and the bearer token keeps working for its remaining lifetime. Make logout call both the BFF session teardown and the token revocation endpoint, and accept that the revocation window for already-issued access tokens is their remaining lifetime.

The 40 embeds are the real schedule risk. A first-party cookie is not sent in a third-party context under current browser partitioning, so embeds cannot use the BFF session at all. They need either their own token-based flow with a narrow audience, or partitioned cookies, and either way the work is in 40 partners' release cycles, not yours. Plan one to two quarters, almost all of it waiting.

The point of no return

Disabling the implicit grant. Before that, every step is a flag flip. After it, rollback means re-enabling a grant type your security review just banned, so get the embed cohort to zero first and keep the old client registered but grant-less for a month.

When this is the wrong answer

If the SPA is same-origin with its API, already uses short-lived access tokens with rotating refresh tokens, and has a strict content security policy, then PKCE in the browser without a BFF is the cheaper correct answer and the BFF is a server you did not need. The BFF earns its cost when token values must never reach JavaScript, when you need server-side revocation that takes effect immediately, or when a regulator asks who holds the refresh token.