Get a Pentest and security assessment of your IT network.

Cyber Security

SPA Authentication Guide

TL;DR

This guide shows how to add secure authentication to your Single Page Application (SPA). We’ll use a common approach with JSON Web Tokens (JWTs) and focus on best practices for security.

1. Understand the Basics

SPAs are different from traditional websites because they load most of their content dynamically using JavaScript after the initial page load. This means standard cookie-based authentication isn’t ideal, as it’s vulnerable to Cross-Site Scripting (XSS) attacks.

  • JWTs: JSON Web Tokens are a secure way to transmit information between parties as a JSON object. They contain user details and are digitally signed.
  • OAuth 2.0/OpenID Connect: These standards provide frameworks for authentication and authorization, often used with third-party identity providers (like Google or Facebook).

2. Server-Side Authentication

Your server handles the initial login process.

  1. User Credentials: Receive username/password from the SPA (usually via a POST request to an /login endpoint).
  2. Verification: Check credentials against your database.
  3. JWT Generation: If valid, create a JWT containing user information (e.g., user ID, roles). Use a strong secret key for signing.
    // Example using Node.js and jsonwebtoken library
    const jwt = require('jsonwebtoken');
    
    function generateToken(user) {
      return jwt.sign({ userId: user.id, role: user.role }, 'your-secret-key', { expiresIn: '1h' }); // Adjust expiry as needed
    }
    
  4. Return JWT: Send the JWT back to the SPA in the response body (usually as JSON). Do not include it in cookies.

3. Client-Side Storage

The SPA stores the JWT securely.

  1. Local Storage vs. Session Storage: Use local storage for persistent tokens (remember me functionality). Use session storage for temporary tokens that expire when the browser closes.
  2. Avoid Cookies: As mentioned, cookies are less secure in SPAs due to XSS risks.
  3. Store Token Safely: Store the token under a non-obvious key.
    // Example using JavaScript
    localStorage.setItem('authToken', jwtToken);
    

4. Protecting API Routes

Your server needs to verify the JWT before allowing access to protected resources.

  1. Middleware: Implement middleware that intercepts requests to protected routes.
  2. Token Extraction: Extract the token from the Authorization header (usually as a Bearer token).
    // Example using Node.js and Express
    function authenticate(req, res, next) {
      const authHeader = req.headers['authorization'];
      if (!authHeader) return res.status(401).send('No token provided.');
    
      const token = authHeader.split(' ')[1]; // Bearer 
      // ... (verify the token using jwt.verify)
    }
    
  3. JWT Verification: Verify the token’s signature and expiry date.
    jwt.verify(token, 'your-secret-key', (err, user) => {
      if (err) return res.status(403).send('Invalid token.');
      req.user = user; // Attach the user object to the request
      next();
    });
    
  4. Access Control: Check if the user has the necessary permissions (roles) to access the resource.

5. Refresh Tokens

JWTs have a limited lifespan. Use refresh tokens for long-term sessions.

  1. Generate Refresh Token: When the user logs in, generate a separate, longer-lived refresh token and store it securely on the server (e.g., in a database).
  2. Refresh Endpoint: Create an endpoint (/refresh) that accepts the refresh token.
  3. Verify & Generate New Token: Verify the refresh token against your database. If valid, generate a new JWT and a new refresh token.
    // Example logic (simplified)
    if (isValidRefreshToken(refreshToken)) {
      const newJwt = generateToken({ userId: user.id, role: user.role });
      const newRefreshToken = generateRefreshToken();
      storeRefreshToken(newRefreshToken, user.id);
      return res.json({ token: newJwt, refreshToken: newRefreshToken });
    }
    
  4. Client-Side Usage: The SPA uses the refresh token to obtain a new JWT when the current one expires.

6. Security Considerations

  • HTTPS: Always use HTTPS to protect data in transit.
  • XSS Protection: Implement robust XSS prevention measures (e.g., Content Security Policy, input validation).
  • CSRF Protection: While less common in SPAs than traditional websites, consider CSRF protection if your SPA interacts with third-party APIs.
  • Secret Key Management: Store your JWT secret key securely and never expose it in client-side code. Use environment variables.
  • Token Expiry: Keep token expiry times reasonably short to minimize the impact of compromised tokens.
Related posts
Cyber Security

Zip Codes & PII: Are They Personal Data?

Cyber Security

Zero-Day Vulnerabilities: User Defence Guide

Cyber Security

Zero Knowledge Voting with Trusted Server

Cyber Security

ZeroNet: 51% Attack Risks & Mitigation