Secure JWT Cookie & CSRF Token Auth

5.2.0 · active · verified Wed Apr 22

Auth-vir is a JavaScript/TypeScript library designed to simplify and secure authentication mechanisms in web applications. It provides robust features for handling JWT (JSON Web Token) based session cookies, CSRF (Cross-Site Request Forgery) protection through tokens, and secure password hashing. The library is actively maintained, with the current stable version being 5.2.0. Releases typically follow a semantic versioning approach, with minor and patch updates occurring every few weeks to months, and major versions introducing breaking changes less frequently, as observed from recent release history. Its key differentiators include a focus on security best practices out-of-the-box, offering both backend and frontend client implementations, and explicit support for ESM (ECMAScript Modules) and browser environments, ensuring modern application compatibility. It aims to abstract away common auth complexities while maintaining high security standards.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates setting up a basic Node.js server using auth-vir for user login, generating secure JWT and CSRF tokens, and authenticating subsequent requests. It shows password hashing, token generation, and user ID extraction from request headers.

import {type ClientRequest, type ServerResponse} from 'node:http';
import {
    AuthCookie,
    doesPasswordMatchHash,
    extractUserIdFromRequestHeaders,
    generateNewJwtKeys,
    generateSuccessfulLoginHeaders,
    hashPassword,
    parseJwtKeys,
    type CookieParams,
    type CreateJwtParams,
    type CsrfHeaderNameOption,
} from 'auth-vir';

type MyUserId = string;

// Generate JWT keys (do this once and store securely, e.g., in environment variables)
async function getJwtKeys() {
    const generatedKeys = await generateNewJwtKeys();
    // In a real app, store these securely (e.g., environment variables)
    // For demo purposes, we'll return them directly.
    console.log('Generated JWT Keys (store securely!):', generatedKeys);
    return parseJwtKeys(generatedKeys);
}

const jwtKeysPromise = getJwtKeys();

async function handleLogin(req: ClientRequest, res: ServerResponse, passwordInput: string) {
    const jwtKeys = await jwtKeysPromise;
    const userId: MyUserId = 'user-123'; // Replace with actual user ID after DB lookup
    const storedPasswordHash = await hashPassword('password123'); // From your user database

    if (await doesPasswordMatchHash({ hash: storedPasswordHash, password: passwordInput })) {
        const authHeaders = await generateSuccessfulLoginHeaders({
            jwtKeys,
            userId,
            maxAgeMs: 1000 * 60 * 60 * 24 * 7, // 7 days
            csrfHeaderName: 'csrf-token',
        });

        for (const [headerName, headerValue] of Object.entries(authHeaders)) {
            res.setHeader(headerName, headerValue);
        }
        res.statusCode = 200;
        res.end('Logged in successfully!');
    } else {
        res.statusCode = 401;
        res.end('Invalid credentials.');
    }
}

async function handleAuthenticatedRequest(req: ClientRequest, res: ServerResponse) {
    const jwtKeys = await jwtKeysPromise;
    try {
        const userId = await extractUserIdFromRequestHeaders({
            jwtKeys,
            requestHeaders: req.headers as Record<string, string | string[] | undefined>,
            csrfHeaderName: 'csrf-token',
        });

        res.statusCode = 200;
        res.end(`Access granted for user ID: ${userId}`);
    } catch (error) {
        console.error('Authentication error:', error);
        res.statusCode = 401;
        res.end('Unauthorized or invalid session.');
    }
}

// Example usage (simplified HTTP server)
import { createServer } from 'node:http';

const server = createServer(async (req, res) => {
    if (req.url === '/login' && req.method === 'POST') {
        // In a real app, parse body for password
        await handleLogin(req, res, 'password123');
    } else if (req.url === '/protected' && req.method === 'GET') {
        await handleAuthenticatedRequest(req, res);
    } else {
        res.statusCode = 404;
        res.end('Not Found');
    }
});

server.listen(3000, () => {
    console.log('Server running on http://localhost:3000');
});

view raw JSON →