Level 02 — Standard

HTTPS + JWT Authentication

HTTPS plus a login system with tokens. This is what 99% of real apps do — including yours, probably.

01What it actually is

→ Real-world example

Flipkart, Swiggy, your bank's online portal, any SaaS dashboard. Your project will use this as the baseline — JWT auth on every protected endpoint is non-negotiable.

02Node.js side

Three things to build: a login endpoint that issues tokens, a middleware that verifies them, and any number of protected routes that depend on that middleware.

1 — Login endpoint (issues a token)

server.js — auth endpoints
JavaScript
const express = require('express');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');

const app = express();
app.use(express.json());

const SECRET = process.env.JWT_SECRET;

// 1. Login endpoint — gives back a token
app.post('/api/login', async (req, res) => {
  const { email, password } = req.body;
  const user = await User.findOne({ email });

  if (!user || !await bcrypt.compare(password, user.passwordHash)) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }

  // Sign a JWT with user info
  const token = jwt.sign(
    { userId: user.id, email: user.email },
    SECRET,
    { expiresIn: '1h' }
  );

  res.json({ token });
});

2 — Middleware (verifies the token on every protected request)

middleware/auth.js
JavaScript
function authMiddleware(req, res, next) {
  const authHeader = req.headers.authorization;
  if (!authHeader) return res.status(401).json({ error: 'No token' });

  const token = authHeader.replace('Bearer ', '');
  try {
    req.user = jwt.verify(token, SECRET);  // attaches user to request
    next();
  } catch {
    res.status(401).json({ error: 'Invalid token' });
  }
}

3 — Protected routes use the middleware

routes/orders.js
JavaScript
app.get('/api/my-orders', authMiddleware, async (req, res) => {
  // req.user.userId came from the token
  const orders = await Order.find({ userId: req.user.userId });
  res.json(orders);
});

03Angular side

Two pieces: a service that handles login and stores the token, and an HTTP interceptor that automatically attaches the token to every outgoing request. Once the interceptor is wired up, the rest of your app doesn't need to think about auth at all.

1 — AuthService

auth.service.ts
TypeScript
@Injectable({ providedIn: 'root' })
export class AuthService {
  constructor(private http: HttpClient) {}

  login(email: string, password: string) {
    return this.http.post<{token: string}>('/api/login', { email, password })
      .pipe(tap(res => localStorage.setItem('token', res.token)));
  }

  getToken() { return localStorage.getItem('token'); }
  logout()   { localStorage.removeItem('token'); }
}

2 — HTTP Interceptor (adds the token to every request)

auth.interceptor.ts
TypeScript
// auth.interceptor.ts — adds token to EVERY request automatically
export const authInterceptor: HttpInterceptorFn = (req, next) => {
  const token = inject(AuthService).getToken();

  if (token) {
    req = req.clone({
      setHeaders: { Authorization: `Bearer ${token}` }
    });
  }
  return next(req);
};

3 — Components stay clean

orders.component.ts
TypeScript
// Component — no auth code needed, interceptor handles it
ngOnInit() {
  this.http.get('/api/my-orders').subscribe(orders => this.orders = orders);
}

04What it protects (and what it doesn't)

Threat Protected? Why / Why not
Random unauthenticated user calls a protected endpoint Yes Middleware rejects requests without a valid token.
A user trying to access another user's data Yes The token identifies which user, and queries filter by req.user.userId.
Stolen token (XSS, leaked from device) No Anyone with the token is the user — until it expires.
Server-side log capture of req.body No Logged requests show plaintext payloads. Level 3 fixes this.

05Key takeaways