TypeScript CSRF/Session Auth Handler
libts-csrfx-auth is a TypeScript-first library designed for managing web session authentication, including CSRF token handling and cookie persistence. Currently at stable version 1.0.3, it has a recent and active release cadence, evidenced by several minor releases following its 1.0.0 major launch. Inspired by Rust's `cekunit-client`, this library focuses on providing a minimal yet robust solution for client-side or web automation authentication flows. Its core utility lies in abstracting the complexities of session management, secure CSRF token exchange, and automatically maintaining authentication state via HTTP cookies, making it suitable for applications requiring resilient and secure web session handling in Node.js or Bun environments.
Common errors
-
TypeError: AuthHandler is not a constructor
cause Attempting to instantiate `AuthHandler` without `new` keyword, or incorrect import (e.g., CommonJS `require` when only ESM default export is available, or vice-versa).fixEnsure you are using `new AuthHandler(...)` and that your import statement is `import { AuthHandler } from 'libts-csrfx-auth';` for ESM environments, or ensure correct CommonJS syntax if the library supports it. Verify your build system handles TypeScript modules correctly. -
Error: CSRF token mismatch
cause The CSRF token sent with a request does not match the token expected by the server. This can be due to an expired token, an invalid token (e.g., after logout/re-login), or a server-side misconfiguration.fixClear browser cookies and session storage, then re-authenticate. Verify the `csrfTokenEndpoint` is correctly configured and the server is consistently setting and validating CSRF tokens. Ensure no caching issues are serving stale tokens. -
Failed to fetch
cause Generic network error indicating the client could not reach the API endpoint. This could be due to incorrect `apiBaseUrl`, server being down, CORS issues, or browser network restrictions.fixCheck `apiBaseUrl` for typos. Verify your backend server is running and accessible from the client's origin. Inspect browser developer tools (Network tab) for specific HTTP errors (e.g., 404, 500, CORS related errors). Ensure `fetch` API is available in your environment (Node.js >=18, Bun, browser). -
Property 'username' does not exist on type 'AuthHandlerConfig'.
cause Attempting to pass authentication credentials directly into `AuthHandlerConfig` instead of the `login` method.fixThe `AuthHandlerConfig` is for setting up the handler itself (endpoints, storage, fetch function). User credentials like `username` and `password` should be passed to the `login` method as arguments, for example: `authHandler.login({ username: 'user', password: 'pass' });`
Warnings
- breaking Major version 1.0.0 likely introduced breaking changes compared to 0.x. While specific details were not provided in the excerpt, major version bumps commonly indicate significant API overhauls or changes in expected behavior.
- gotcha Improper handling of CSRF tokens on the server-side can still lead to vulnerabilities, even when using this client-side library. The library facilitates token management, but the server must correctly issue, validate, and rotate tokens.
- gotcha Relying solely on client-side storage (e.g., `localStorage`) for authentication tokens is less secure than `HttpOnly` cookies. If the `storage` configuration in `AuthHandler` uses insecure methods, it increases vulnerability to XSS attacks.
- gotcha The `apiBaseUrl` configuration must accurately reflect your backend's base URL. Mismatches can lead to `CORS` issues, failed requests, or incorrect cookie domain handling, preventing session persistence.
Install
-
npm install libts-csrfx-auth -
yarn add libts-csrfx-auth -
pnpm add libts-csrfx-auth
Imports
- AuthHandler
const { AuthHandler } = require('libts-csrfx-auth');import { AuthHandler } from 'libts-csrfx-auth'; - AuthHandlerConfig
import { AuthHandlerConfig } from 'libts-csrfx-auth';import type { AuthHandlerConfig } from 'libts-csrfx-auth'; - AuthError
import AuthError from 'libts-csrfx-auth/dist/AuthError';
import { AuthError } from 'libts-csrfx-auth';
Quickstart
import { AuthHandler } from 'libts-csrfx-auth';
interface MyApiCredentials {
username: string;
password: string;
}
// Simulate a backend API
const API_BASE_URL = 'http://localhost:3000';
const authHandler = new AuthHandler({
apiBaseUrl: API_BASE_URL,
loginEndpoint: '/auth/login',
logoutEndpoint: '/auth/logout',
csrfTokenEndpoint: '/auth/csrf-token',
// In a real app, use a secure, persistent storage mechanism (e.g., localStorage, secure cookies)
// For this example, we'll use a simple in-memory store.
storage: {
get: (key) => {
console.log(`[Storage] Getting ${key}`);
return localStorage.getItem(key);
},
set: (key, value) => {
console.log(`[Storage] Setting ${key}=${value}`);
localStorage.setItem(key, value);
},
remove: (key) => {
console.log(`[Storage] Removing ${key}`);
localStorage.removeItem(key);
}
},
// Custom fetch function to intercept and add tokens/cookies
fetch: async (input, init) => {
const response = await fetch(input, {
...init,
headers: {
'Content-Type': 'application/json',
// Assuming AuthHandler automatically manages Cookie and X-CSRF-Token
...(init?.headers || {})
}
});
if (!response.ok) {
console.error(`API Error: ${response.status} ${response.statusText}`);
}
return response;
}
});
async function runAuthFlow() {
const credentials: MyApiCredentials = {
username: process.env.TEST_USERNAME ?? 'testuser',
password: process.env.TEST_PASSWORD ?? 'testpass'
};
try {
console.log('--- Attempting Login ---');
await authHandler.login(credentials);
console.log('Login successful! Session should be active.');
console.log('\n--- Fetching CSRF Token ---');
const csrfToken = await authHandler.getCSRFToken();
console.log(`Received CSRF Token: ${csrfToken ? csrfToken.substring(0, 10) + '...' : 'none'}`);
console.log('\n--- Making a Protected Request (e.g., update profile) ---');
// In a real scenario, `fetch` would be wrapped by AuthHandler to inject CSRF token
const protectedResponse = await authHandler.fetch(`${API_BASE_URL}/profile`, {
method: 'POST',
body: JSON.stringify({ name: 'Jane Doe' })
});
if (protectedResponse.ok) {
console.log('Protected request successful!');
} else {
console.error('Protected request failed.');
}
console.log('\n--- Attempting Logout ---');
await authHandler.logout();
console.log('Logout successful! Session should be terminated.');
} catch (error) {
console.error('Authentication flow failed:', error);
}
}
// Note: For a real example, you'd need a mock server at http://localhost:3000
// that handles /auth/login, /auth/logout, /auth/csrf-token, and /profile.
// The server should set 'Set-Cookie' headers for session and CSRF tokens
// and validate 'X-CSRF-Token' for POST requests.
runAuthFlow();