Lesson 25 of 30
Knowing what a token is doesn't tell you where it gets attached, or what happens when ten requests are in flight the instant it expires. Those are data-layer implementation problems, not auth theory.
13 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 3
An app adds the Authorization header manually at each individual fetch call site instead of through one shared wrapper. What real bug does this practice tend to produce?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
This lesson assumes the mechanics of tokens and sessions are already familiar — this platform's frontend-practices coverage goes through JWTs versus sessions in depth, and that reasoning isn't repeated here. What's covered here instead is narrower and more code-shaped: once a token exists, how does the code that actually fetches data attach it, and what happens when it expires in the middle of a session with real requests in flight?
Two concrete problems live in the fetching layer specifically:
let accessToken: string | null = getStoredAccessToken();
let refreshPromise: Promise<string> | null = null;
async function refreshAccessToken(): Promise<string> {
// If a refresh is already underway, every caller awaits that same
// promise instead of starting a second, independent refresh request.
if (!refreshPromise) {
refreshPromise = fetch("/api/auth/refresh", { method: "POST", credentials: "include" })
.then((res) => {
if (!res.ok) throw new Error("Refresh failed");
return res.json();
})
.then((data) => {
accessToken = data.accessToken;
return data.accessToken as string;
})
.finally(() => {
refreshPromise = null; // clear it so the next expiry starts a fresh refresh
});
}
return refreshPromise;
}
async function apiFetch(path: string, options: RequestInit = {}): Promise<Response> {
const withAuth = (token: string | null): RequestInit => ({
...options,
headers: { ...options.headers, ...(token ? { Authorization: `Bearer ${token}` } : {}) },
});
let res = await fetch(path, withAuth(accessToken));
if (res.status === 401) {
const newToken = await refreshAccessToken();
res = await fetch(path, withAuth(newToken));
}
return res;
}
Every call site just calls apiFetch, so the header is attached the same way everywhere and no individual caller can forget it. The important detail is refreshPromise: if three requests all hit a 401 within the same tick because the access token expired, all three call refreshAccessToken, but only the first one actually starts a new refresh request — the other two await the exact same in-flight promise and reuse its result.
"How does your app handle a token expiring while multiple requests are in flight?" is a specific, practical question that separates candidates who've only described token mechanics from those who've actually hit and fixed the concurrent-refresh race condition.