npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@aid-on/auth

v1.0.1

Published

Edge-native authentication with Fluent API. Sessions, OAuth, Guests, Audit logs. Zero Node.js dependencies.

Readme

@aid-on/auth

Edge-native authentication library with Fluent API for Cloudflare Workers

Zero Node.js dependencies. Pure Web Crypto API.

// Fluent API - Simple, Type-safe, Powerful
await SessionBuilder.create(user).withSecret(secret).withDuration('7d').build()
await GuestBuilder.create().withSessionDuration('24h').build()
await OAuthFlow.google().withClientId(id).buildAuthUrl()
await AuditBuilder.login(userId).fromRequest(request).build()

Features

  • Session Management - HMAC-SHA256 signed sessions with key rotation support
  • Guest Users - Anonymous authentication with automatic expiration
  • OAuth 2.0 - Complete OAuth flow with CSRF protection (Google, GitHub, custom)
  • Audit Logging - Flexible audit trail with storage-agnostic design
  • Cloudflare Access - Zero Trust integration support
  • Unicode Support - Full support for Japanese, emoji, and all Unicode characters
  • Edge Native - Built for Cloudflare Workers, no Node.js dependencies
  • Fluent API - Intuitive method chaining for better DX

Installation

npm install @aid-on/auth

Quick Start

Session Management

import { SessionBuilder, SessionVerifier } from '@aid-on/auth/session';

// Create session
const session = await SessionBuilder
  .create({ id: user.id, email: user.email, name: user.name })
  .withSecret(env.SESSION_SECRET)
  .withDuration('7d')  // '24h', '30m', '60s' or milliseconds
  .build();

// Set cookie
return new Response('Success', {
  headers: { 'Set-Cookie': session.cookieString }
});

// Verify session
const result = await SessionVerifier
  .fromRequest(request)
  .withSecret(env.SESSION_SECRET)
  .verify();

if (result.valid) {
  console.log('User:', result.payload);
}

Guest Users

import { GuestBuilder, isGuestId } from '@aid-on/auth/guest';

// Create guest user
const { user, session } = await GuestBuilder
  .create()
  .withName('Guest')
  .withSessionDuration('24h')
  .withSecret(env.SESSION_SECRET)
  .build();

// Check if user is guest
if (isGuestId(userId)) {
  // Handle guest user
}

OAuth 2.0 Flow (with CSRF Protection)

import { OAuthFlow, OAuthCallback, generateState, verifyState, createStateCookie } from '@aid-on/auth/oauth';

// 1. Generate auth URL with state parameter
const state = generateState('/dashboard'); // Optional redirect after auth
const authUrl = OAuthFlow
  .google()
  .withClientId(env.GOOGLE_CLIENT_ID)
  .withRedirectUri('https://example.com/callback')
  .withState(state) // CSRF protection
  .withOfflineAccess()
  .buildAuthUrl();

// Store state in cookie for later verification
return Response.redirect(authUrl, {
  headers: {
    'Set-Cookie': createStateCookie(state),
  },
});

// 2. Handle callback with state verification
const url = new URL(request.url);
const receivedState = url.searchParams.get('state');
const storedState = extractStateFromCookies(request.headers.get('Cookie') || '');

// Verify state to prevent CSRF attacks
try {
  verifyState(receivedState, storedState);
} catch (error) {
  return new Response('Invalid state - possible CSRF attack', { status: 403 });
}

// Exchange code for tokens
const result = await OAuthCallback
  .fromUrl(request.url)
  .withClientId(env.GOOGLE_CLIENT_ID)
  .withClientSecret(env.GOOGLE_CLIENT_SECRET)
  .exchange();

if (result.success) {
  // Parse state to get redirect URL
  const stateData = parseState(storedState!);
  
  // Create session
  const session = await SessionBuilder
    .create(result.user)
    .withSecret(env.SESSION_SECRET)
    .build();
    
  return Response.redirect(stateData.redirectTo || '/', {
    headers: {
      'Set-Cookie': session.cookieString,
    },
  });
}

Audit Logging

import { AuditBuilder } from '@aid-on/auth/audit';

// Log authentication events
const entry = AuditBuilder
  .login(user.id)
  .fromRequest(request)
  .withDetails({ provider: 'google' })
  .build();

// Store in your preferred storage (D1, DO, KV, etc.)
await storeAuditLog(entry);

Cloudflare Access Integration

import { accessGuard } from '@aid-on/auth/access';

// Protect routes with CF Access
const auth = await accessGuard(request, env, {
  getTeamDomain: (env) => env.CF_TEAM_DOMAIN,
  allowDevBypass: true,
});

if (!auth.success) {
  return auth.errorResponse;
}

API Reference

@aid-on/auth/session

class SessionBuilder {
  static create(payload: SessionPayload): SessionBuilder
  withSecret(secret: string): this
  withDuration(duration: string | number): this
  withCookie(options: SessionCookieOptions): this
  asAuthenticated(): this  // 7 days default
  asGuest(): this          // 24 hours default
  build(): Promise<SessionCreateResult>
}

class SessionVerifier {
  static fromToken(token: string): SessionVerifier
  static fromRequest(request: Request): SessionVerifier
  static fromCookies(cookieHeader: string): SessionVerifier
  withSecret(secret: string): this
  withSecrets(secrets: string[]): this  // Key rotation support
  skipExpiryCheck(): this
  verify(): Promise<SessionVerifyResult>
  verifyOrThrow(): Promise<SessionPayload>
}

@aid-on/auth/guest

class GuestBuilder {
  static create(): GuestBuilder
  withIdPrefix(prefix: string): this
  withName(name: string): this
  withEmailDomain(domain: string): this
  withSessionDuration(duration: string | number): this
  withSecret(secret: string): this
  withMetadata(metadata: Record<string, unknown>): this
  build(): Promise<GuestCreateResult>
}

function isGuestId(userId: string, prefix?: string): boolean
function parseGuestEmail(guestId: string, domain?: string): string

@aid-on/auth/oauth

class OAuthFlow {
  static google(): OAuthFlow
  static github(): OAuthFlow  // GitHub support
  static custom(config: OAuthProviderConfig): OAuthFlow  // Custom providers
  withClientId(clientId: string): this
  withRedirectUri(uri: string): this
  withScope(scope: string): this
  withState(state: string): this
  withRandomState(): this
  withOfflineAccess(): this
  buildAuthUrl(): string
}

class OAuthCallback {
  static fromUrl(url: string | URL, provider?: string | OAuthProviderConfig): OAuthCallback
  static google(): OAuthCallback
  static github(): OAuthCallback
  static custom(config: OAuthProviderConfig): OAuthCallback
  withClientId(clientId: string): this
  withClientSecret(clientSecret: string): this
  withRedirectUri(uri: string): this
  exchange(): Promise<OAuthCallbackResult>
  exchangeForUser(): Promise<OAuthUserInfo | null>
}

// State parameter helpers for CSRF protection
function generateState(redirectTo?: string, metadata?: object): string
function parseState(state: string, maxAge?: number): StateData
function verifyState(received: string, stored: string): void
function createStateCookie(state: string, options?: CookieOptions): string
function extractStateFromCookies(cookieHeader: string): string | null

@aid-on/auth/audit

class AuditBuilder {
  static create(action: AuditAction): AuditBuilder
  static login(userId: string): AuditBuilder
  static loginFailed(userId: string, reason?: string): AuditBuilder
  static logout(userId: string): AuditBuilder
  static guestLogin(guestId: string): AuditBuilder
  withUser(userId: string): this
  fromRequest(request: Request): this
  withDetails(details: Record<string, unknown>): this
  withError(message: string): this
  build(): AuditLog
  logWith(logger: AuditLogger): Promise<void>
}

function extractAuditInfo(request: Request): AuditInfo

@aid-on/auth/access

function accessGuard(request: Request, env: Env, options: AccessOptions): Promise<AuthResult>
function getAuthContext(request: Request, options: AccessOptions): Promise<AuthContext>

Duration Formats

// String formats
.withDuration('7d')     // 7 days
.withDuration('24h')    // 24 hours
.withDuration('30m')    // 30 minutes
.withDuration('60s')    // 60 seconds

// Milliseconds
.withDuration(86400000) // 1 day in ms

// Presets
.asAuthenticated()      // 7 days
.asGuest()             // 24 hours

Real-world Example

Complete authentication flow in a Cloudflare Pages Function:

import { Hono } from 'hono';
import { SessionBuilder, SessionVerifier } from '@aid-on/auth/session';
import { GuestBuilder } from '@aid-on/auth/guest';
import { OAuthFlow, OAuthCallback } from '@aid-on/auth/oauth';
import { AuditBuilder } from '@aid-on/auth/audit';

const app = new Hono();

// OAuth login
app.get('/auth/login', (c) => {
  const authUrl = OAuthFlow
    .google()
    .withClientId(c.env.GOOGLE_CLIENT_ID)
    .withRedirectUri(`${c.req.url.origin}/auth/callback`)
    .buildAuthUrl();
  
  return c.redirect(authUrl);
});

// OAuth callback
app.get('/auth/callback', async (c) => {
  const result = await OAuthCallback
    .fromUrl(c.req.url)
    .withClientId(c.env.GOOGLE_CLIENT_ID)
    .withClientSecret(c.env.GOOGLE_CLIENT_SECRET)
    .exchange();

  if (!result.success) {
    return c.json({ error: result.error }, 400);
  }

  // Create session
  const session = await SessionBuilder
    .create(result.user)
    .withSecret(c.env.SESSION_SECRET)
    .withDuration('7d')
    .build();

  // Audit log
  await AuditBuilder
    .login(result.user.id)
    .fromRequest(c.req.raw)
    .logWith(auditLogger);

  return c.redirect('/', {
    headers: { 'Set-Cookie': session.cookieString }
  });
});

// Guest login
app.post('/auth/guest', async (c) => {
  const { user, session } = await GuestBuilder
    .create()
    .withSessionDuration('24h')
    .withSecret(c.env.SESSION_SECRET)
    .build();

  return c.json({ user }, {
    headers: { 'Set-Cookie': session.cookieString }
  });
});

// Protected route
app.get('/api/user', async (c) => {
  const result = await SessionVerifier
    .fromRequest(c.req.raw)
    .withSecret(c.env.SESSION_SECRET)
    .verify();

  if (!result.valid) {
    return c.json({ error: 'Unauthorized' }, 401);
  }

  return c.json({ user: result.payload });
});

Advanced Features

Session Key Rotation

Rotate secrets without logging out users:

// Old secret still works during transition
const result = await SessionVerifier
  .fromRequest(request)
  .withSecrets([
    env.SESSION_SECRET_NEW,  // Try new secret first
    env.SESSION_SECRET_OLD,  // Fall back to old secret
  ])
  .verify();

Custom OAuth Providers

Add any OAuth 2.0 provider:

const discordFlow = OAuthFlow.custom({
  authUrl: 'https://discord.com/oauth2/authorize',
  tokenUrl: 'https://discord.com/api/oauth2/token',
  userInfoUrl: 'https://discord.com/api/users/@me',
  defaultScope: 'identify email',
});

const authUrl = discordFlow
  .withClientId(env.DISCORD_CLIENT_ID)
  .buildAuthUrl();

Unicode and International Support

Full support for international characters:

// Works perfectly with Japanese names, emoji, etc.
const session = await SessionBuilder
  .create({
    id: 'user-123',
    email: '[email protected]',
    name: '田中太郎',
  })
  .withSecret(secret)
  .build();

Why @aid-on/auth?

Production-Tested

Extracted from fast-llm-chat, serving real users in production on Cloudflare Pages.

Security-First

  • CSRF protection built into OAuth flow
  • Session key rotation without downtime
  • HMAC-SHA256 signatures
  • Secure defaults (HttpOnly, Secure, SameSite cookies)

True Edge Native

  • Zero Node.js dependencies - Pure Web Crypto API
  • No polyfills - Built for V8 isolates
  • Lightweight - ~8KB total
  • Fast - Optimized for Cloudflare Workers

Developer Experience

  • Fluent API - Intuitive method chaining
  • Type-safe - Full TypeScript support with inference
  • Well-documented - Comprehensive examples
  • Extensible - Easy to add custom providers

License

MIT