ASVS 5.0 V10.1.1 requires that tokens are sent only to components that strictly need them. The standard's example is a browser single page app using a backend for frontend (BFF), where access and refresh tokens are available only to the backend. It is a Level 2 requirement.
Why it matters
Every place a token travels is a place it can leak. A token in browser storage can be stolen by any script that runs on the page, including one injected through an XSS bug or a compromised third party library. A token passed to a logging pipeline, an analytics tool or a downstream service that does not need it can end up in files and dashboards that many people read.
How to implement it
Use a BFF. The browser talks to your backend with an ordinary session cookie. The backend holds the OAuth tokens and attaches them when calling APIs.
// BFF endpoint: the browser never sees the access token
app.get("/api/orders", requireSession, async (req, res) => {
const accessToken = await tokenStore.getAccessToken(req.session.id);
const upstream = await fetch("https://orders.internal/orders", {
headers: { Authorization: "Bearer " + accessToken },
});
res.status(upstream.status).json(await upstream.json());
});
// session cookie settings
app.use(session({
cookie: { httpOnly: true, secure: true, sameSite: "lax", path: "/" },
}));
Other places to trim token exposure:
- Do not put tokens in URLs, query strings or fragments that end up in history and referrer headers.
- Redact
Authorizationheaders and token fields in logs, traces and error reports. - Forward tokens only to services that are the intended audience, and use narrower tokens for downstream calls.
- Keep refresh tokens server side only.
How to test it
- Open the browser developer tools. Search local storage, session storage, IndexedDB and non-HttpOnly cookies for token strings. You should find none.
- Search network traces for
Authorizationheaders sent from the browser to third party domains. - Grep application logs and tracing output for
Bearerand for long base64 strings starting witheyJ. - Check that no third party script, analytics call or error report contains a token.
You can also scan your repositories and build logs for committed credentials with the secrets scanning demo.
Common mistakes
- Storing tokens in
localStoragebecause it is easy. - Logging full request headers during debugging.
- Passing the user's token to every internal service regardless of need.
- Placing a token in a redirect URL.
Try it yourself
Click through it at your own pace, or open it full screen.
Quick check
What does a BFF change for token handling?
The browser holds only a session cookie. Access and refresh tokens stay on the backend.
Is a token in a URL fragment safe?
No. It can leak through history, screenshots and scripts, and it widens exposure for no benefit.