@bambsdev/auth
v1.4.13
Published
> π **The Complete Authentication Solution** for Hono, Cloudflare Workers (Edge Runtime), and Drizzle ORM.
Keywords
Readme
@bambsdev/auth
π The Complete Authentication Solution for Hono, Cloudflare Workers (Edge Runtime), and Drizzle ORM.
@bambsdev/auth (v1.4.0) is a production-ready, type-safe, multi-database authentication library designed specifically for the Cloudflare Workers ecosystem. It provides everything from standard JWT auth and family-based refresh token rotation to Google OAuth, AI-moderated avatar uploads (Cloudflare R2 + Workers AI), customizable verification flows (OTP / Link), and automated OpenAPI/Swagger documentation.
π Architecture & Tech Stack
This package follows a Clean Service Layer Architecture. Business logic is strictly decoupled from routing and infrastructure, ensuring high testability, modularity, and edge runtime compatibility.
Core Technologies
- Framework: Hono (powered by
@hono/zod-openapifor automatic OpenAPI/Swagger documentation) - Runtime: Cloudflare Workers (Edge Serverless)
- Multi-Database Support:
- PostgreSQL: Subpath
@bambsdev/auth/pgvia Cloudflare Hyperdrive /node-postgres - Cloudflare D1 (SQLite): Subpath
@bambsdev/auth/d1via Cloudflare native D1 Edge Database - Shared Core: Root
@bambsdev/authfor shared types, utilities, and schemas
- PostgreSQL: Subpath
- ORM: Drizzle ORM
- Storage: Cloudflare R2 (for avatar storage & orphan cleanup)
- State & Caching: Two-tier caching (Cloudflare Cache API L1 + Cloudflare KV L2) for rate limiting, blacklisting, and OAuth CSRF states
- AI Moderation: Cloudflare Workers AI (
@cf/microsoft/resnet-50for image safety classification) - Observability: Cloudflare Analytics Engine (for non-blocking audit logging)
- Email Service: Resend API via native
fetch(for OTP codes, verification links, and password resets)
β¨ Key Features
π‘οΈ Core Authentication & Session Management
- Token Rotation & Grace Period (Leeway Window): Refresh token rotation with family-based tracking and a 30-second leeway window (RFC 6749 / Auth0 standard) to handle spam reloads and concurrent requests seamlessly. If an old token is reused outside the grace period, all tokens in the family are automatically revoked.
- Strict Session Limits (Max 10): Prevents session hoarding by automatically revoking the oldest session (FIFO) when a user exceeds 10 active devices/sessions.
- Session Control: List active devices, revoke individual sessions, or execute a global "Logout from all devices" command.
- Ultra-Low Cost Rate Limiting (CF Cache API L1 + Lazy KV): Failed attempts are tracked in free L1 Cache API; KV is only written when brute-force threshold is breached, eliminating up to 95% of KV write operations.
- Adaptive Cookie Management: Configurable cookie name (
COOKIE_NAME) and domain (COOKIE_DOMAIN) withHttpOnly,Secure, and adaptiveSameSite(Laxfor first-party root sharing,Nonefor cross-site dev/preview environments). - Two-Tier Edge Cache: L1 Cache API + L2 KV caching with negative caching (
"0") reducing KV read costs by up to 99%.
π² Cross-Client Session Handoff (Mobile-to-Web SSO)
- One-Time Magic Ticket: Enables seamless session transfer from mobile applications to mobile browsers / web checkout without forcing users to re-enter credentials.
- Zero Replay Attacks: Tokens are cryptographically secure 64-character hex strings stored temporarily in Cloudflare KV with a short TTL (default 180s / 3 minutes) and destroyed immediately upon exchange.
- Target Redirection: Supports optional
redirectUrlparameter to route users directly to specific destinations (e.g. checkout, invoice, or library) with active session state.
π¨ Flexible Email Verification & Password Reset
- Verification Modes: Choose between 6-digit numeric OTP codes or URL verification links (
verificationMethod: "code" | "link"). - Customizable Templates: Fully customizable email templates and configurable OTP TTL.
- Secure Password Reset: Transactional password reset with 64-character hex tokens and automatic invalidation of old unused tokens.
- Password Reuse Prevention: Rejects password changes if the new password is identical to the current one.
π Google OAuth 2.0 & RFC 7636 PKCE
- Zero-KV OAuth Flow & PKCE Defense: Full RFC 7636 PKCE (
code_challengeS256 +code_verifier) with signed HttpOnly cookie storage (oauth_session), eliminating 100% of KV reads/writes during Google login. - Web Flow: Standard redirect flow with RFC 6750 compliant URL Fragment delivery (
#accessToken=...) preventing token leakage in logs and referrers. - Mobile Flow: Direct Google ID token verification via Native SDKs (Android/iOS).
- Smart Account Linking: Atomically links Google logins to existing accounts with matching email addresses.
- Open Redirect Protection: Strict fail-closed validation of redirect URLs against
ALLOWED_ORIGINS(supports wildcard subdomains like*.example.pages.devorhttps://*.pages.dev) andAPP_URL.
π€ Avatar Uploads (Cloudflare R2 + Workers AI Moderation)
- Built-in AI Moderation: Uses
@cf/microsoft/resnet-50to classify uploaded avatars. - SSRF Protection: Strict URL validation blocking private IPs, metadata endpoints (
169.254.169.254), and localhost before fetching images. - Automatic Storage Cleanup: Deletes old avatar files from R2 automatically upon new upload or deletion.
- R2 Proxy Endpoint: Built-in streaming proxy route for R2 files when custom domains are not configured.
π¦ Subpath Package Exports
| Subpath | Dialect / Target | Database Middleware | Primary Use Case |
| :--- | :--- | :--- | :--- |
| @bambsdev/auth/pg | PostgreSQL | dbMiddleware | Cloudflare Workers using Hyperdrive / PostgreSQL |
| @bambsdev/auth/d1 | Cloudflare D1 | dbMiddleware | Cloudflare Workers using native Cloudflare D1 (SQLite) |
| @bambsdev/auth | Core Agnostic | N/A | Shared schemas, types, error utilities, and helpers |
π Installation & Setup
1. Install the Package
bun add @bambsdev/auth2. Peer Dependencies
Install the peer dependencies required for your database choice:
# For PostgreSQL Workers:
bun add hono @hono/zod-openapi drizzle-orm pg zod
# For Cloudflare D1 Workers (zero pg dependencies needed):
bun add hono @hono/zod-openapi drizzle-orm zodβ‘ Quick Start Examples
Option A: PostgreSQL Worker (@bambsdev/auth/pg)
import { Hono } from "hono";
import { authRoutes, settingRoutes, dbMiddleware } from "@bambsdev/auth/pg";
import type { PgBindings, PgVariables } from "@bambsdev/auth/pg";
import type { EmailConfig } from "@bambsdev/auth";
const app = new Hono<{ Bindings: PgBindings; Variables: PgVariables }>();
// Injects Drizzle PostgreSQL client into context
app.use("*", dbMiddleware);
// Optional Email Configuration
const emailConfig: EmailConfig = {
from: "No-Reply <[email protected]>",
verificationMethod: "code", // "code" (OTP) | "link" (URL)
verificationCodeTtlMinutes: 10,
resetPasswordBaseUrl: "https://myapp.com",
};
app.use("*", async (c, next) => {
c.set("emailConfig", emailConfig);
// Optional Image Filter Configuration (AI Moderation)
c.set("imageFilterConfig", {
enabled: true, // set to false to bypass AI moderation
failOpenOnAiError: true, // allow upload if Workers AI service errors or is unreachable
confidenceThreshold: 0.50, // detection threshold (default: 0.15)
allowAvatarUpload: true, // Optional: set to false to disable avatar uploads (default: true)
});
await next();
});
// Mount routes
app.route("/auth", authRoutes);
app.route("/api/settings", settingRoutes);
export default app;Option B: Cloudflare D1 Worker (@bambsdev/auth/d1)
import { Hono } from "hono";
import { authRoutes, settingRoutes, dbMiddleware } from "@bambsdev/auth/d1";
import type { D1Bindings, D1Variables } from "@bambsdev/auth/d1";
import type { EmailConfig } from "@bambsdev/auth";
const app = new Hono<{ Bindings: D1Bindings; Variables: D1Variables }>();
// Injects Drizzle D1 client into context
app.use("*", dbMiddleware);
// Mount routes
app.route("/auth", authRoutes);
app.route("/api/settings", settingRoutes);
export default app;βοΈ Wrangler Configuration
Example wrangler.jsonc configuration:
{
"name": "my-auth-worker",
"main": "src/index.ts",
"compatibility_date": "2024-09-23",
"vars": {
"APP_URL": "https://myapp.com",
"ALLOWED_ORIGINS": "https://myapp.com,https://admin.myapp.com,https://*.pages.dev",
"COOKIE_NAME": "my_auth_rf", // Optional, defaults to "refresh_token"
"COOKIE_DOMAIN": ".myapp.com", // Optional, enables first-party root cookie sharing
"COOKIE_SAME_SITE": "Lax", // Optional, "Lax" | "Strict" | "None"
"REFRESH_TOKEN_GRACE_PERIOD_SECONDS": "30", // Optional, grace period in seconds (default: 30)
"ALLOW_AVATAR_UPLOAD": "true", // Optional: "true" (default) or "false" to disable avatar uploads
"EMAIL_FROM": "No-Reply <[email protected]>",
"BUCKET_PUBLIC_URL": "https://pub-xxx.r2.dev",
"GOOGLE_CLIENT_ID": "xxx.apps.googleusercontent.com",
"GOOGLE_CLIENT_SECRET": "GOCSPX-xxx",
"GOOGLE_ALLOWED_CLIENT_IDS": "android-client-id,ios-client-id",
"JWT_SECRET": "your-jwt-access-secret-min-32-chars",
"JWT_REFRESH_SECRET": "your-jwt-refresh-secret-min-32-chars",
"RESEND_API_KEY": "re_xxx"
},
// For PostgreSQL:
"hyperdrive": [
{ "binding": "HYPERDRIVE", "id": "<your-hyperdrive-id>" }
],
// For Cloudflare D1:
"d1_databases": [
{ "binding": "DB", "database_name": "my-auth-db", "database_id": "<your-d1-id>" }
],
"kv_namespaces": [
{ "binding": "KV", "id": "<your-kv-id>" }
],
"r2_buckets": [
{ "binding": "R2_PUBLIC", "bucket_name": "my-avatars" }
],
"ai": { "binding": "AI" },
"analytics_engine_datasets": [
{ "binding": "ANALYTICS" }
]
}π§Ή Scheduled Token Cleanups (Cron Trigger)
Clean up expired refresh tokens, verification tokens, and password reset records periodically:
PostgreSQL:
import {
cleanupExpiredTokens,
cleanupExpiredPasswordResets,
cleanupExpiredEmailVerifications,
} from "@bambsdev/auth/pg";
export default {
async scheduled(event, env, ctx) {
const conn = env.LOCAL_DATABASE_URL || env.HYPERDRIVE?.connectionString;
ctx.waitUntil(cleanupExpiredTokens(conn));
ctx.waitUntil(cleanupExpiredPasswordResets(conn));
ctx.waitUntil(cleanupExpiredEmailVerifications(conn));
},
};Cloudflare D1:
import {
cleanupExpiredTokensD1,
cleanupExpiredPasswordResetsD1,
cleanupExpiredEmailVerificationsD1,
} from "@bambsdev/auth/d1";
export default {
async scheduled(event, env, ctx) {
ctx.waitUntil(cleanupExpiredTokensD1(env.DB));
ctx.waitUntil(cleanupExpiredPasswordResetsD1(env.DB));
ctx.waitUntil(cleanupExpiredEmailVerificationsD1(env.DB));
},
};πΊοΈ API Reference
π Auth Endpoints (/auth)
| Method | Path | Access | Rate Limit | Description |
| :------- | :-------------------------- | :--------- | :--------- | :----------------------------------------------------- |
| POST | /auth/register | Public | - | Register new user with email, password, and username |
| POST | /auth/login | Public | 5 / 5 min | Login with email & password, returns JWT token pair |
| POST | /auth/refresh | Public | 5 / 5 min | Rotate refresh token (supports JSON body or HttpOnly Cookie) |
| POST | /auth/logout | π Private | - | Logout current device session (supports JSON body or Cookie) |
| POST | /auth/logout-all | π Private | - | Revoke all active sessions across all devices |
| GET | /auth/sessions | π Private | - | List all active sessions with device info |
| DELETE | /auth/sessions/:id | π Private | - | Revoke a specific session ID |
| GET | /auth/verify-email | Public | - | Verify email via 64-character hex link token |
| POST | /auth/verify-email-code | Public | 5 / 5 min | Verify email via 6-digit numeric OTP code |
| POST | /auth/resend-verification | Public | 3 / 5 min | Resend verification code or link |
| GET | /auth/google/login | Public | - | Redirect to Google OAuth consent screen (Web flow) |
| GET | /auth/google/callback | Public | - | Handle Google redirect, returns token in URL fragment |
| POST | /auth/google/token | Public | 5 / 5 min | Verify Google ID token from Native Mobile SDK |
| POST | /auth/forgot-password | Public | 3 / 5 min | Request password reset link email |
| POST | /auth/reset-password | Public | 10 / 5 min | Reset password using 64-character hex token |
| POST | /auth/handoff/token | π Private | - | Generate short-lived one-time handoff token for Web SSO (alias: /auth/handoff-token) |
| POST | /auth/handoff/exchange | Public | 5 / 5 min | Exchange one-time handoff token for Web session (accessToken + HttpOnly cookie) |
π€ Settings Endpoints (/api/settings)
| Method | Path | Access | Description |
| :------- | :------------------------------ | :--------- | :-------------------------------------------------- |
| GET | /api/settings/profile | π Private | Get authenticated user profile |
| PUT | /api/settings/profile | π Private | Update username (case-insensitive) or full name |
| PUT | /api/settings/password | π Private | Change password (revokes old device sessions) |
| PUT | /api/settings/avatar | π Private | Upload avatar file (Multipart, AI safety check, R2). Returns 403 if disabled via ALLOW_AVATAR_UPLOAD. |
| DELETE | /api/settings/avatar | π Private | Delete avatar and clean up physical file from R2 |
| GET | /api/settings/avatar-file/* | Public | Streaming proxy for avatar images from R2 |
π Documentation Guides
- MIGRATION.md: Comprehensive multi-database migration and configuration guide.
- CHANGELOG.md: Detailed release notes and breaking changes history.
π License
ISC License
