Async & Promisesmedium

Implement auth guards and API interceptors in a React app

Design frontend auth guards and API request/response interceptors for a SaaS application. Cover session loading, token refresh, 401 vs 403 handling, route protection, capabilities, and security limits.

Asked at PlainID

#authentication#authorization#API clients#route guards#security

Answer

Interview framing: Auth guards and interceptors improve UX and consistency, but they are not the final security boundary. Backend enforcement is mandatory.

Auth guard responsibilities:

  • Wait for initial session loading before redirecting.
  • Redirect unauthenticated users to login and preserve the intended destination.
  • Show unauthorized or request-access states for authenticated users without required capability.
  • Avoid flicker by modeling loading, authenticated, unauthenticated, and forbidden states explicitly.

API client responsibilities:

  • Attach auth/session headers consistently.
  • Add request IDs or correlation IDs when useful.
  • Normalize errors into a predictable shape.
  • Handle 401 by refreshing session or redirecting to login.
  • Handle 403 as authenticated but not allowed.
  • Cancel stale requests where interactions change quickly.

Example shape:

async function request<T>(path: string, options: RequestInit = {}): Promise<T> {
  const response = await fetch(path, {
    ...options,
    headers: {
      ...options.headers,
      Authorization: `Bearer ${getAccessToken()}`,
    },
  })

  if (response.status === 401) throw new AuthError('Session expired')
  if (response.status === 403) throw new ForbiddenError('Not allowed')
  if (!response.ok) throw await toApiError(response)
  return response.json() as Promise<T>
}

Security limits:

  • Do not trust localStorage role flags for enforcement.
  • Do not expose sensitive data and then hide it in the UI.
  • Every sensitive API must validate permissions server-side.

Good closing: "The frontend should make auth state understandable and consistent, while the backend remains responsible for the actual access decision."

Source: Senior frontend interview research

Practise more Async & Promises questions →