跪拜 Guibai
← All articles
React.js · Axios · JavaScript

JWT Authentication, End to End: How a Token Gets Signed, Stored, Carried, Verified, and Guarded

By 烬羽 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Most developers learn JWT by memorizing `sign` and `verify` without understanding the full request lifecycle. Seeing the five-stage chain—and why the payload is encoded rather than encrypted, why the token lives in two frontend stores, and how the interceptor and guard fit together—turns scattered API knowledge into a coherent mental model that makes debugging authentication failures straightforward.

Summary

JWT authentication is often reduced to calling `sign` and `verify`, but the real understanding comes from tracing a token's entire journey. The process breaks into five linked stages: the backend signs a payload with a secret to produce a tamper-proof token; the frontend stores it in both localStorage for persistence and a Zustand store for reactivity; an Axios request interceptor attaches it to every outgoing request; the backend verifies the signature without any database lookup; and a React route guard component redirects unauthenticated users before protected pages render.

A key clarification is that the JWT payload is Base64-encoded, not encrypted—anyone can decode it. Security relies entirely on the signature, which is an HMAC of the header and payload using a server-side secret. This makes the token self-verifying and stateless, which is why JWT replaced server-side sessions in distributed systems: any machine with the secret can validate the token, eliminating the need for shared session storage.

The frontend storage pattern addresses two separate concerns. localStorage survives page refreshes, while the Zustand store triggers UI re-renders when authentication state changes. The interceptor pattern centralizes a cross-cutting concern, and the route guard component follows React's declarative philosophy by expressing access control at the routing layer rather than inside individual pages.

Takeaways
JWT payloads use Base64 encoding, not encryption; anyone can decode them, and security comes from the signature preventing tampering.
The signature is an HMAC of the encoded header and payload using a server-side secret, so any content change invalidates it.
JWT's core advantage over sessions is statelessness: any server with the secret can verify the token without shared storage.
Frontend tokens are stored in both localStorage (persistence across refreshes) and a Zustand store (reactive UI updates) because persistence and reactivity are separate concerns.
An Axios request interceptor centralizes attaching the Authorization header, applying a cross-cutting concern once instead of at every call site.
A response interceptor that returns `res.data` unwraps the AxiosResponse object so business code receives the response body directly.
The backend `jwt.verify` call confirms authenticity using only the secret and the token itself, with no database query.
A React route guard component like `RequireAuth` keeps access control at the routing layer, following declarative patterns rather than scattering checks inside pages.
Conclusions

Storing the token in two places—localStorage and Zustand—is not redundancy but a clean separation of persistence from reactivity, a distinction that applies to nearly all frontend state.

The interceptor pattern is an example of aspect-oriented programming in the frontend: extracting a cross-cutting concern (auth headers) from business logic so it's configured once and applied everywhere.

Understanding that the response interceptor unwraps `AxiosResponse` explains why some codebases access `res.data` and others don't—it depends on whether that unwrapping convention is in place.

The declarative route guard (`<RequireAuth><Pay /></RequireAuth>`) is more maintainable than imperative checks inside components because it makes access policy visible at the route definition level.

Concepts & terms
JWT (JSON Web Token)
A compact, URL-safe token consisting of three Base64-encoded segments separated by dots: a header declaring the signing algorithm, a payload containing claims (identity, expiry), and a signature that prevents tampering. The payload is encoded, not encrypted.
Base64 encoding
A reversible encoding scheme that represents binary data using 64 printable ASCII characters. Unlike encryption, it requires no key and provides no confidentiality—anyone can decode it.
HMAC signature
A hash-based message authentication code produced by combining the encoded header and payload with a secret key. The backend recalculates it on each request to verify the token hasn't been altered.
Stateless authentication
An approach where the server stores no session data. The token itself carries all necessary identity information, and any server holding the secret can validate it independently.
Axios interceptor
A middleware function that runs before requests are sent or after responses are received, used to centralize cross-cutting concerns like attaching auth headers or unwrapping response objects.
Route guard
A component that wraps protected routes and conditionally renders children or redirects based on authentication state, keeping access control at the routing layer rather than inside page components.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗