{"_id":"@aid-on/auth","name":"@aid-on/auth","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.1":{"name":"@aid-on/auth","version":"1.0.1","description":"Edge-native authentication with Fluent API. Sessions, OAuth, Guests, Audit logs. Zero Node.js dependencies.","exports":{".":{"types":"./dist/session/index.d.ts","import":"./dist/session/index.js","default":"./dist/session/index.js"},"./session":{"types":"./dist/session/index.d.ts","import":"./dist/session/index.js","default":"./dist/session/index.js"},"./guest":{"types":"./dist/guest/index.d.ts","import":"./dist/guest/index.js","default":"./dist/guest/index.js"},"./oauth":{"types":"./dist/oauth/index.d.ts","import":"./dist/oauth/index.js","default":"./dist/oauth/index.js"},"./audit":{"types":"./dist/audit/index.d.ts","import":"./dist/audit/index.js","default":"./dist/audit/index.js"},"./access":{"types":"./dist/cloudflare-access/index.d.ts","import":"./dist/cloudflare-access/index.js","default":"./dist/cloudflare-access/index.js"}},"scripts":{"build":"tsc","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest"},"keywords":["cloudflare-workers","edge-auth","fluent-api","session-management","oauth","guest-users","audit-log","web-crypto"],"license":"MIT","devDependencies":{"@cloudflare/workers-types":"^4.20241205.0","happy-dom":"^20.0.11","typescript":"^5.0.0","vitest":"^1.0.0"},"_id":"@aid-on/auth@1.0.1","_nodeVersion":"20.19.6","_npmVersion":"10.8.2","dist":{"integrity":"sha512-f6OZK/natynbZ7s21UDdIYjGfUTp2hUPFkjwF4HLjL2HBC9NJFELZAJp4RNdr4/u448/Jhi5pC3QQZM+he0ekg==","shasum":"15f3fb2c54e19c6dde1cdbe2344a09bc4ffd134b","tarball":"https://registry.npmjs.org/@aid-on/auth/-/auth-1.0.1.tgz","fileCount":98,"unpackedSize":162915,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIEDwRf1vDLRPTBE1es4+nOSySIAbirfpdNZGkBnqcfqvAiAv5XuXAcqtziGspRvdP5ahAmTpMJCeUU9ZBKHqBRze9Q=="}]},"_npmUser":{"name":"aid-on","email":"hiromi.motodera@aid-on.org"},"directories":{},"maintainers":[{"name":"aid-on","email":"hiromi.motodera@aid-on.org"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/auth_1.0.1_1771435109286_0.9348515026146129"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-18T17:18:29.189Z","1.0.1":"2026-02-18T17:18:29.448Z","modified":"2026-02-18T17:18:29.674Z"},"maintainers":[{"name":"aid-on","email":"hiromi.motodera@aid-on.org"}],"description":"Edge-native authentication with Fluent API. Sessions, OAuth, Guests, Audit logs. Zero Node.js dependencies.","keywords":["cloudflare-workers","edge-auth","fluent-api","session-management","oauth","guest-users","audit-log","web-crypto"],"license":"MIT","readme":"# @aid-on/auth\n\n**Edge-native authentication library with Fluent API for Cloudflare Workers**\n\nZero Node.js dependencies. Pure Web Crypto API.\n\n```typescript\n// Fluent API - Simple, Type-safe, Powerful\nawait SessionBuilder.create(user).withSecret(secret).withDuration('7d').build()\nawait GuestBuilder.create().withSessionDuration('24h').build()\nawait OAuthFlow.google().withClientId(id).buildAuthUrl()\nawait AuditBuilder.login(userId).fromRequest(request).build()\n```\n\n## Features\n\n- **Session Management** - HMAC-SHA256 signed sessions with key rotation support\n- **Guest Users** - Anonymous authentication with automatic expiration\n- **OAuth 2.0** - Complete OAuth flow with CSRF protection (Google, GitHub, custom)\n- **Audit Logging** - Flexible audit trail with storage-agnostic design\n- **Cloudflare Access** - Zero Trust integration support\n- **Unicode Support** - Full support for Japanese, emoji, and all Unicode characters\n- **Edge Native** - Built for Cloudflare Workers, no Node.js dependencies\n- **Fluent API** - Intuitive method chaining for better DX\n\n## Installation\n\n```bash\nnpm install @aid-on/auth\n```\n\n## Quick Start\n\n### Session Management\n\n```typescript\nimport { SessionBuilder, SessionVerifier } from '@aid-on/auth/session';\n\n// Create session\nconst session = await SessionBuilder\n  .create({ id: user.id, email: user.email, name: user.name })\n  .withSecret(env.SESSION_SECRET)\n  .withDuration('7d')  // '24h', '30m', '60s' or milliseconds\n  .build();\n\n// Set cookie\nreturn new Response('Success', {\n  headers: { 'Set-Cookie': session.cookieString }\n});\n\n// Verify session\nconst result = await SessionVerifier\n  .fromRequest(request)\n  .withSecret(env.SESSION_SECRET)\n  .verify();\n\nif (result.valid) {\n  console.log('User:', result.payload);\n}\n```\n\n### Guest Users\n\n```typescript\nimport { GuestBuilder, isGuestId } from '@aid-on/auth/guest';\n\n// Create guest user\nconst { user, session } = await GuestBuilder\n  .create()\n  .withName('Guest')\n  .withSessionDuration('24h')\n  .withSecret(env.SESSION_SECRET)\n  .build();\n\n// Check if user is guest\nif (isGuestId(userId)) {\n  // Handle guest user\n}\n```\n\n### OAuth 2.0 Flow (with CSRF Protection)\n\n```typescript\nimport { OAuthFlow, OAuthCallback, generateState, verifyState, createStateCookie } from '@aid-on/auth/oauth';\n\n// 1. Generate auth URL with state parameter\nconst state = generateState('/dashboard'); // Optional redirect after auth\nconst authUrl = OAuthFlow\n  .google()\n  .withClientId(env.GOOGLE_CLIENT_ID)\n  .withRedirectUri('https://example.com/callback')\n  .withState(state) // CSRF protection\n  .withOfflineAccess()\n  .buildAuthUrl();\n\n// Store state in cookie for later verification\nreturn Response.redirect(authUrl, {\n  headers: {\n    'Set-Cookie': createStateCookie(state),\n  },\n});\n\n// 2. Handle callback with state verification\nconst url = new URL(request.url);\nconst receivedState = url.searchParams.get('state');\nconst storedState = extractStateFromCookies(request.headers.get('Cookie') || '');\n\n// Verify state to prevent CSRF attacks\ntry {\n  verifyState(receivedState, storedState);\n} catch (error) {\n  return new Response('Invalid state - possible CSRF attack', { status: 403 });\n}\n\n// Exchange code for tokens\nconst result = await OAuthCallback\n  .fromUrl(request.url)\n  .withClientId(env.GOOGLE_CLIENT_ID)\n  .withClientSecret(env.GOOGLE_CLIENT_SECRET)\n  .exchange();\n\nif (result.success) {\n  // Parse state to get redirect URL\n  const stateData = parseState(storedState!);\n  \n  // Create session\n  const session = await SessionBuilder\n    .create(result.user)\n    .withSecret(env.SESSION_SECRET)\n    .build();\n    \n  return Response.redirect(stateData.redirectTo || '/', {\n    headers: {\n      'Set-Cookie': session.cookieString,\n    },\n  });\n}\n```\n\n### Audit Logging\n\n```typescript\nimport { AuditBuilder } from '@aid-on/auth/audit';\n\n// Log authentication events\nconst entry = AuditBuilder\n  .login(user.id)\n  .fromRequest(request)\n  .withDetails({ provider: 'google' })\n  .build();\n\n// Store in your preferred storage (D1, DO, KV, etc.)\nawait storeAuditLog(entry);\n```\n\n### Cloudflare Access Integration\n\n```typescript\nimport { accessGuard } from '@aid-on/auth/access';\n\n// Protect routes with CF Access\nconst auth = await accessGuard(request, env, {\n  getTeamDomain: (env) => env.CF_TEAM_DOMAIN,\n  allowDevBypass: true,\n});\n\nif (!auth.success) {\n  return auth.errorResponse;\n}\n```\n\n## API Reference\n\n### `@aid-on/auth/session`\n\n```typescript\nclass SessionBuilder {\n  static create(payload: SessionPayload): SessionBuilder\n  withSecret(secret: string): this\n  withDuration(duration: string | number): this\n  withCookie(options: SessionCookieOptions): this\n  asAuthenticated(): this  // 7 days default\n  asGuest(): this          // 24 hours default\n  build(): Promise<SessionCreateResult>\n}\n\nclass SessionVerifier {\n  static fromToken(token: string): SessionVerifier\n  static fromRequest(request: Request): SessionVerifier\n  static fromCookies(cookieHeader: string): SessionVerifier\n  withSecret(secret: string): this\n  withSecrets(secrets: string[]): this  // Key rotation support\n  skipExpiryCheck(): this\n  verify(): Promise<SessionVerifyResult>\n  verifyOrThrow(): Promise<SessionPayload>\n}\n```\n\n### `@aid-on/auth/guest`\n\n```typescript\nclass GuestBuilder {\n  static create(): GuestBuilder\n  withIdPrefix(prefix: string): this\n  withName(name: string): this\n  withEmailDomain(domain: string): this\n  withSessionDuration(duration: string | number): this\n  withSecret(secret: string): this\n  withMetadata(metadata: Record<string, unknown>): this\n  build(): Promise<GuestCreateResult>\n}\n\nfunction isGuestId(userId: string, prefix?: string): boolean\nfunction parseGuestEmail(guestId: string, domain?: string): string\n```\n\n### `@aid-on/auth/oauth`\n\n```typescript\nclass OAuthFlow {\n  static google(): OAuthFlow\n  static github(): OAuthFlow  // GitHub support\n  static custom(config: OAuthProviderConfig): OAuthFlow  // Custom providers\n  withClientId(clientId: string): this\n  withRedirectUri(uri: string): this\n  withScope(scope: string): this\n  withState(state: string): this\n  withRandomState(): this\n  withOfflineAccess(): this\n  buildAuthUrl(): string\n}\n\nclass OAuthCallback {\n  static fromUrl(url: string | URL, provider?: string | OAuthProviderConfig): OAuthCallback\n  static google(): OAuthCallback\n  static github(): OAuthCallback\n  static custom(config: OAuthProviderConfig): OAuthCallback\n  withClientId(clientId: string): this\n  withClientSecret(clientSecret: string): this\n  withRedirectUri(uri: string): this\n  exchange(): Promise<OAuthCallbackResult>\n  exchangeForUser(): Promise<OAuthUserInfo | null>\n}\n\n// State parameter helpers for CSRF protection\nfunction generateState(redirectTo?: string, metadata?: object): string\nfunction parseState(state: string, maxAge?: number): StateData\nfunction verifyState(received: string, stored: string): void\nfunction createStateCookie(state: string, options?: CookieOptions): string\nfunction extractStateFromCookies(cookieHeader: string): string | null\n```\n\n### `@aid-on/auth/audit`\n\n```typescript\nclass AuditBuilder {\n  static create(action: AuditAction): AuditBuilder\n  static login(userId: string): AuditBuilder\n  static loginFailed(userId: string, reason?: string): AuditBuilder\n  static logout(userId: string): AuditBuilder\n  static guestLogin(guestId: string): AuditBuilder\n  withUser(userId: string): this\n  fromRequest(request: Request): this\n  withDetails(details: Record<string, unknown>): this\n  withError(message: string): this\n  build(): AuditLog\n  logWith(logger: AuditLogger): Promise<void>\n}\n\nfunction extractAuditInfo(request: Request): AuditInfo\n```\n\n### `@aid-on/auth/access`\n\n```typescript\nfunction accessGuard(request: Request, env: Env, options: AccessOptions): Promise<AuthResult>\nfunction getAuthContext(request: Request, options: AccessOptions): Promise<AuthContext>\n```\n\n## Duration Formats\n\n```typescript\n// String formats\n.withDuration('7d')     // 7 days\n.withDuration('24h')    // 24 hours\n.withDuration('30m')    // 30 minutes\n.withDuration('60s')    // 60 seconds\n\n// Milliseconds\n.withDuration(86400000) // 1 day in ms\n\n// Presets\n.asAuthenticated()      // 7 days\n.asGuest()             // 24 hours\n```\n\n## Real-world Example\n\nComplete authentication flow in a Cloudflare Pages Function:\n\n```typescript\nimport { Hono } from 'hono';\nimport { SessionBuilder, SessionVerifier } from '@aid-on/auth/session';\nimport { GuestBuilder } from '@aid-on/auth/guest';\nimport { OAuthFlow, OAuthCallback } from '@aid-on/auth/oauth';\nimport { AuditBuilder } from '@aid-on/auth/audit';\n\nconst app = new Hono();\n\n// OAuth login\napp.get('/auth/login', (c) => {\n  const authUrl = OAuthFlow\n    .google()\n    .withClientId(c.env.GOOGLE_CLIENT_ID)\n    .withRedirectUri(`${c.req.url.origin}/auth/callback`)\n    .buildAuthUrl();\n  \n  return c.redirect(authUrl);\n});\n\n// OAuth callback\napp.get('/auth/callback', async (c) => {\n  const result = await OAuthCallback\n    .fromUrl(c.req.url)\n    .withClientId(c.env.GOOGLE_CLIENT_ID)\n    .withClientSecret(c.env.GOOGLE_CLIENT_SECRET)\n    .exchange();\n\n  if (!result.success) {\n    return c.json({ error: result.error }, 400);\n  }\n\n  // Create session\n  const session = await SessionBuilder\n    .create(result.user)\n    .withSecret(c.env.SESSION_SECRET)\n    .withDuration('7d')\n    .build();\n\n  // Audit log\n  await AuditBuilder\n    .login(result.user.id)\n    .fromRequest(c.req.raw)\n    .logWith(auditLogger);\n\n  return c.redirect('/', {\n    headers: { 'Set-Cookie': session.cookieString }\n  });\n});\n\n// Guest login\napp.post('/auth/guest', async (c) => {\n  const { user, session } = await GuestBuilder\n    .create()\n    .withSessionDuration('24h')\n    .withSecret(c.env.SESSION_SECRET)\n    .build();\n\n  return c.json({ user }, {\n    headers: { 'Set-Cookie': session.cookieString }\n  });\n});\n\n// Protected route\napp.get('/api/user', async (c) => {\n  const result = await SessionVerifier\n    .fromRequest(c.req.raw)\n    .withSecret(c.env.SESSION_SECRET)\n    .verify();\n\n  if (!result.valid) {\n    return c.json({ error: 'Unauthorized' }, 401);\n  }\n\n  return c.json({ user: result.payload });\n});\n```\n\n## Advanced Features\n\n### Session Key Rotation\n\nRotate secrets without logging out users:\n\n```typescript\n// Old secret still works during transition\nconst result = await SessionVerifier\n  .fromRequest(request)\n  .withSecrets([\n    env.SESSION_SECRET_NEW,  // Try new secret first\n    env.SESSION_SECRET_OLD,  // Fall back to old secret\n  ])\n  .verify();\n```\n\n### Custom OAuth Providers\n\nAdd any OAuth 2.0 provider:\n\n```typescript\nconst discordFlow = OAuthFlow.custom({\n  authUrl: 'https://discord.com/oauth2/authorize',\n  tokenUrl: 'https://discord.com/api/oauth2/token',\n  userInfoUrl: 'https://discord.com/api/users/@me',\n  defaultScope: 'identify email',\n});\n\nconst authUrl = discordFlow\n  .withClientId(env.DISCORD_CLIENT_ID)\n  .buildAuthUrl();\n```\n\n### Unicode and International Support\n\nFull support for international characters:\n\n```typescript\n// Works perfectly with Japanese names, emoji, etc.\nconst session = await SessionBuilder\n  .create({\n    id: 'user-123',\n    email: 'tanaka@example.com',\n    name: '田中太郎',\n  })\n  .withSecret(secret)\n  .build();\n```\n\n## Why @aid-on/auth?\n\n### Production-Tested\n\nExtracted from [fast-llm-chat](https://github.com/Aid-On/fast-llm-chat), serving real users in production on Cloudflare Pages.\n\n### Security-First\n\n- CSRF protection built into OAuth flow\n- Session key rotation without downtime\n- HMAC-SHA256 signatures\n- Secure defaults (HttpOnly, Secure, SameSite cookies)\n\n### True Edge Native\n\n- **Zero Node.js dependencies** - Pure Web Crypto API\n- **No polyfills** - Built for V8 isolates\n- **Lightweight** - ~8KB total\n- **Fast** - Optimized for Cloudflare Workers\n\n### Developer Experience\n\n- **Fluent API** - Intuitive method chaining\n- **Type-safe** - Full TypeScript support with inference\n- **Well-documented** - Comprehensive examples\n- **Extensible** - Easy to add custom providers\n\n## License\n\nMIT","readmeFilename":"README.md","_rev":"1-eea7e889eeaeddd50840afe7bb29eac2"}