Adding Authentication to React AppsEntry 10 of 11

Security Notes and Project Structure

Practical security limits of client-side auth, and where the auth pieces live.

Notes

  • Client-side checks are UX, not security. Hiding buttons and redirecting from routes can be bypassed. The backend must validate the token on every protected request.
  • localStorage is readable by any script on the page, so an XSS vulnerability can steal the token. Alternatives:
    • httpOnly cookies set by the server: JavaScript can't read them, and the browser sends them automatically (requires CSRF protection).
    • Short-lived access token in memory + refresh token in an httpOnly cookie: the common production pattern.
  • Never log tokens or put them in URLs.
  • Match the frontend expiration to the backend's, or decode the JWT's exp claim instead of hardcoding a duration.

Code compare

React
src/├── App.tsx                  // routes: root (id, tokenLoader), auth, logout, protected loaders├── util/│   └── auth.ts              // store/get/clear token, tokenLoader, checkAuthLoader├── services/│   ├── auth.ts              // authenticate()│   ├── http.ts              // authFetch()│   └── events.ts├── pages/│   ├── Root.tsx             // auto logout timer│   ├── Authentication.tsx   // + action│   └── Logout.ts            // action only└── components/    ├── AuthForm.tsx    └── MainNavigation.tsx   // conditional links
Angular
src/app/├── app.config.ts            // provideHttpClient(withInterceptors([authInterceptor]))├── app.routes.ts├── core/│   ├── auth/│   │   ├── auth.service.ts  // token signal, login/signup, logout, timer│   │   ├── auth.guard.ts│   │   ├── auth.interceptor.ts│   │   └── auth.component.ts│   └── layout/main-navigation.component.ts└── events/    └── events.routes.ts     // canActivate: [authGuard]