Frontend Security: Best Practices for Authentication and Authorization 2024

Introduction

In modern web applications, understanding the difference between authentication and authorization is crucial. While they often go hand in hand, they serve distinct purposes. This blog post explores these concepts from a frontend perspective, dives into various token storage methods, and discusses security implications to prepare you for real-world implementation and interviews.


1. Understanding Authentication vs. Authorization

  • Authentication: The process of verifying a user’s identity (i.e., “Who are you?”).
  • Authorization: The process of determining what an authenticated user can access (i.e., “What can you do?”).

Analogy: Think of authentication as checking your identity with an ID card, and authorization as the permissions you have once inside the building.


2. Types of Authentication

  • Single-Factor Authentication (SFA): Uses one factor (e.g., a password).
  • Multi-Factor Authentication (MFA): Uses multiple factors (e.g., password + OTP).
  • Social Login: Authentication via third-party providers (e.g., Google, Facebook).
  • Token-Based Authentication: Utilizes tokens (e.g., JSON Web Tokens – JWT) to authenticate users.

3. Token-Based Authentication

Token-based authentication involves sending a token to the client upon successful login, which the client stores and includes in subsequent requests to identify itself.

Example Token Structure:

{
  "header": {
    "alg": "HS256",
    "typ": "JWT"
  },
  "payload": {
    "userId": "123",
    "role": "admin",
    "exp": 1716915234
  },
  "signature": "generatedSignature"
}

Key Points:

  • The header specifies the algorithm used.
  • The payload contains user information.
  • The signature ensures the token’s integrity.

4. Where to Store Tokens on the Frontend?

a) localStorage

Pros:

  • Easy to implement
  • Persistent even after the browser is closed

Cons:

  • Vulnerable to Cross-Site Scripting (XSS) attacks
  • Any script on the page can access the token

Example Usage:

// Storing token
localStorage.setItem('authToken', token);

// Retrieving token
const token = localStorage.getItem('authToken');

b) sessionStorage

Pros:

  • Token is cleared when the browser/tab is closed
  • Less vulnerable than localStorage to unauthorized access

Cons:

  • Vulnerable to XSS attacks
  • Not shared across tabs or windows

Example Usage:

// Storing token
sessionStorage.setItem('authToken', token);

// Retrieving token
const token = sessionStorage.getItem('authToken');

c) HTTP-Only Cookies

Pros:

  • Secure against XSS attacks as JavaScript cannot access httpOnly cookies
  • Suitable for sensitive data like tokens

Cons:

  • Vulnerable to Cross-Site Request Forgery (CSRF) attacks if not handled correctly

Example Usage:
The server sets an HTTP-only cookie:

res.cookie('authToken', token, {
    httpOnly: true,
    secure: true, // Only transmit over HTTPS
    sameSite: 'Strict' // Prevent CSRF
});

Interview Insight: Storing tokens in HTTP-only cookies is generally more secure than using localStorage or sessionStorage.

d) In-Memory Storage

Pros:

  • Most secure against XSS attacks
  • Token is stored only while the page is active

Cons:

  • Token is lost on page refresh
  • Suitable mainly for single-page applications (SPAs)

Example Usage:

let authToken = null;

function setToken(token) {
    authToken = token;
}

function getToken() {
    return authToken;
}

5. Security Considerations

a) Preventing XSS Attacks

  • Content Security Policy (CSP): Set CSP headers to restrict the sources of executable scripts.
  • Input Sanitization: Always sanitize user inputs.

b) Preventing CSRF Attacks

  • Use sameSite and httpOnly attributes for cookies.
  • Implement CSRF tokens for requests.

c) Token Expiry and Refresh Mechanism

  • Set a reasonable exp claim in JWTs.
  • Implement a refresh token mechanism to obtain new access tokens.

6. Implementing Token-Based Authentication

Login and Storing Token Example:

Login Function:

async function login(username, password) {
    const response = await fetch('/api/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ username, password })
    });

    if (response.ok) {
        const data = await response.json();
        localStorage.setItem('authToken', data.token);
    } else {
        console.error('Login failed');
    }
}

Attaching Token to Requests:

async function fetchData() {
    const token = localStorage.getItem('authToken');

    const response = await fetch('/api/data', {
        method: 'GET',
        headers: {
            'Authorization': `Bearer ${token}`
        }
    });

    const data = await response.json();
    console.log(data);
}

7. Common Interview Questions and Detailed Answers

Q1: What is the difference between authentication and authorization?

Answer:

  • Authentication verifies the user’s identity.
  • Authorization determines what an authenticated user can access.

Q2: Where should you store tokens on the frontend, and why?

Answer:

  • localStorage: Persistent but vulnerable to XSS attacks.
  • sessionStorage: Short-lived but still vulnerable to XSS.
  • HTTP-only Cookies: More secure against XSS but can be vulnerable to CSRF.
  • In-Memory: Most secure but not persistent.

Best Practice: Use HTTP-only cookies for sensitive tokens.


Q3: How do you prevent XSS attacks when storing tokens?

Answer:

  • Store tokens in HTTP-only cookies to prevent JavaScript access.
  • Implement Content Security Policy (CSP) headers.
  • Always sanitize and escape user inputs.

Q4: How do you handle token expiry and refresh?

Answer:

  • Set an expiration time (exp) in the JWT payload.
  • Use a refresh token to obtain a new access token without requiring the user to log in again.

Example Refresh Mechanism:

async function refreshToken() {
    const response = await fetch('/api/refresh-token', {
        method: 'POST',
        credentials: 'include' // Sends cookie
    });

    if (response.ok) {
        const data = await response.json();
        localStorage.setItem('authToken', data.token);
    }
}

Q5: What are CSRF and XSS attacks, and how can you prevent them?

Answer:

  • CSRF (Cross-Site Request Forgery): An attacker tricks the user into making unauthorized requests.
  • Prevention: Use CSRF tokens, sameSite cookie attribute, and HTTP-only cookies.
  • XSS (Cross-Site Scripting): An attacker injects malicious scripts into a web page.
  • Prevention: Use Content Security Policy (CSP), sanitize inputs, and avoid storing sensitive data in localStorage.

Additional Essential JavaScript Interview Questions on Various Topics

Top Javascript Books to Read

Conclusion

Authentication and authorization are integral parts of frontend security. Understanding token storage options, security vulnerabilities, and best practices will help you build more secure applications. This knowledge is essential not only for interview preparation but also for designing robust real-world web applications.

By mastering these concepts, you’ll be well-equipped to handle token-based authentication and authorization challenges in modern frontend development.

Leave a Comment