API ReferenceAuthentication

Authentication

Overview

This page demonstrates how to implement authentication in your Nextra documentation site.

Basic Authentication

API Key Authentication

// Example API key authentication
const apiKey = 'your-api-key-here';
 
const response = await fetch('/api/data', {
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  }
});

OAuth 2.0 Authentication

// OAuth 2.0 flow example
const oauthConfig = {
  clientId: 'your-client-id',
  clientSecret: 'your-client-secret',
  redirectUri: 'http://localhost:3000/callback',
  scope: 'read write'
};
 
// Step 1: Redirect to authorization server
const authUrl = `https://auth.example.com/oauth/authorize?` +
  `client_id=${oauthConfig.clientId}&` +
  `redirect_uri=${encodeURIComponent(oauthConfig.redirectUri)}&` +
  `scope=${encodeURIComponent(oauthConfig.scope)}&` +
  `response_type=code`;
 
window.location.href = authUrl;

JWT Token Authentication

Creating JWT Tokens

import jwt from 'jsonwebtoken';
 
const payload = {
  userId: 123,
  email: 'user@example.com',
  role: 'admin'
};
 
const token = jwt.sign(payload, 'your-secret-key', {
  expiresIn: '24h'
});

Verifying JWT Tokens

import jwt from 'jsonwebtoken';
 
try {
  const decoded = jwt.verify(token, 'your-secret-key');
  console.log('Decoded token:', decoded);
} catch (error) {
  console.error('Invalid token:', error.message);
}

Session-based Authentication

Express.js Session Example

import express from 'express';
import session from 'express-session';
 
const app = express();
 
app.use(session({
  secret: 'your-session-secret',
  resave: false,
  saveUninitialized: false,
  cookie: {
    secure: process.env.NODE_ENV === 'production',
    maxAge: 24 * 60 * 60 * 1000 // 24 hours
  }
}));
 
// Login route
app.post('/login', (req, res) => {
  const { username, password } = req.body;
  
  // Verify credentials
  if (username === 'admin' && password === 'password') {
    req.session.userId = 123;
    req.session.authenticated = true;
    res.json({ success: true });
  } else {
    res.status(401).json({ error: 'Invalid credentials' });
  }
});
 
// Protected route
app.get('/protected', (req, res) => {
  if (req.session.authenticated) {
    res.json({ message: 'Access granted' });
  } else {
    res.status(401).json({ error: 'Authentication required' });
  }
});

Best Practices

1. Secure Token Storage

// Good: Store tokens in httpOnly cookies
app.use(cookieParser());
 
app.post('/login', (req, res) => {
  // ... authentication logic
  res.cookie('token', token, {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'strict',
    maxAge: 24 * 60 * 60 * 1000
  });
});
 
// Bad: Don't store tokens in localStorage
// localStorage.setItem('token', token); // Avoid this

2. Token Refresh

// Implement token refresh logic
async function refreshToken(refreshToken) {
  try {
    const response = await fetch('/api/refresh', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ refreshToken })
    });
    
    const { accessToken } = await response.json();
    return accessToken;
  } catch (error) {
    console.error('Token refresh failed:', error);
    // Redirect to login
    window.location.href = '/login';
  }
}

3. Error Handling

// Centralized error handling for authentication
class AuthError extends Error {
  constructor(message, statusCode = 401) {
    super(message);
    this.name = 'AuthError';
    this.statusCode = statusCode;
  }
}
 
// Usage
app.get('/api/protected', (req, res, next) => {
  try {
    if (!req.headers.authorization) {
      throw new AuthError('No authorization header', 401);
    }
    
    // ... authentication logic
    
  } catch (error) {
    next(error);
  }
});
 
// Error middleware
app.use((error, req, res, next) => {
  if (error instanceof AuthError) {
    res.status(error.statusCode).json({
      error: error.message
    });
  } else {
    res.status(500).json({
      error: 'Internal server error'
    });
  }
});

Testing Authentication

Unit Tests

import { describe, it, expect, beforeEach } from 'vitest';
import { authenticate } from '../auth';
 
describe('Authentication', () => {
  it('should authenticate valid credentials', async () => {
    const result = await authenticate('admin', 'password');
    expect(result.success).toBe(true);
    expect(result.token).toBeDefined();
  });
  
  it('should reject invalid credentials', async () => {
    const result = await authenticate('admin', 'wrong-password');
    expect(result.success).toBe(false);
    expect(result.error).toBe('Invalid credentials');
  });
});