• Blog
  • Docs
  • Pricing
  • We’re hiring!
Log inSign up
std

std

oauth

Login with Val Town OAuth Middleware
Unlisted
Like
1
oauth
Home
Code
7
README.md
TESTING.md
crypto.ts
H
example.tsx
middleware.ts
oauth.ts
session.ts
Branches
1
Pull requests
Remixes
History
Environment variables
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
README.md
Code
/
README.md
Search
10/29/2025
Viewing readonly version of main branch: v142
View latest version
README.md

Val Town OAuth Library

A middleware library for adding OAuth authentication to Val Town vals using the Val Town OAuth provider.

Features

  • Public Client Flow: Uses OAuth 2.0 Authorization Code flow with PKCE for secure public client authentication
  • Dynamic Client Registration: Automatically registers OAuth clients on-demand
  • State Encryption: Encrypts OAuth state parameter with AES-GCM to prevent tampering
  • Encrypted Session Cookies: Stateless session management using encrypted cookies
  • CSRF Protection: Origin header validation for non-GET requests
  • Hono Middleware: Drop-in middleware for Hono apps

Usage

Create val
/** @jsxImportSource https://esm.sh/hono/jsx */ import { Hono } from "https://esm.sh/hono"; import oauth from "https://esm.town/v/std/oauth/middleware"; const app = new Hono(); app.get("/", (c) => { const userId = c.req.header("X-VT-User-Id"); return c.html( <html> <body> {userId ? <p>Logged in as {userId}</p> : <a href="/auth/login">Log in</a>} </body> </html>, ); }); // Wrap your app with the OAuth middleware export default oauth(app.fetch); // Or customize the options: // export default oauth(app.fetch, { // clientName: "My Custom App Name", // scopes: ["openid", "offline_access", "user_r", "project_r"] // });

Authentication Routes

The middleware automatically handles these routes:

  • /auth/login - Initiates the OAuth flow, redirects to Val Town authorization
  • /auth/callback - Handles the OAuth callback, exchanges code for tokens, and creates session
  • /auth/logout - Logs out the user and clears the session cookie

User Headers

Once authenticated, all requests include these trusted headers:

  • X-VT-User-Id - The Val Town user ID
  • X-VT-User-Email - The user's email address
  • X-VT-User-Name - The user's display name

These headers are set by the middleware after validating the session cookie. Any user-provided X-VT-* headers are removed to ensure they're trusted.

Environment Variables

Optional:

  • OAUTH_STATE_ENCRYPTION_KEY - Secret key for encrypting OAuth state and sessions
    • If not set, a random key will be auto-generated and stored in blob storage
    • Performance tip: Set this to a random value (e.g., openssl rand -base64 32) to dramatically speed up your val by avoiding blob storage lookups on every request
    • The key is cached in memory after first use for optimal performance

Architecture

oauth.ts

Core utilities for OAuth operations:

  • PKCE (Proof Key for Code Exchange) generation
  • State encryption/decryption using AES-GCM
  • Dynamic client registration with Val Town OAuth server
  • State validation with 10-minute expiry

session.ts

Session management utilities:

  • Encrypted session cookie creation and validation
  • 30-day session duration
  • Stateless design - no database required
  • Stores OAuth tokens (access_token, refresh_token, id_token) and user info

middleware.ts

Hono middleware that:

  • Intercepts auth-related routes (/auth/*)
  • Manages the OAuth authorization flow
  • Creates and validates encrypted session cookies
  • Sets trusted user headers
  • Provides CSRF protection for non-GET requests

example.tsx

Demo application showing how to use the middleware

Session Management

Sessions are stored as encrypted cookies with the following characteristics:

  • Storage: Encrypted cookie (stateless, no database)
  • Duration: 30 days (fixed, no rotation)
  • Cookie Settings: HttpOnly, Secure, SameSite=Lax
  • Contents: User ID, email, name, and OAuth tokens (access, refresh, ID)
  • Encryption: AES-GCM using the same key as OAuth state encryption

Accessing OAuth Tokens

While user headers provide basic identity information, the full OAuth tokens (including access tokens for API calls) are stored securely in the encrypted session cookie. To access tokens in your application:

Create val
// The middleware sets these headers for you const userId = c.req.header("X-VT-User-Id"); const userEmail = c.req.header("X-VT-User-Email"); const userName = c.req.header("X-VT-User-Name"); // For accessing OAuth tokens, you'll need to implement a helper // that reads and decrypts the session cookie (similar to how the // middleware does it internally)

Security Features

  • PKCE: Protects against authorization code interception attacks
  • Encrypted State: Prevents CSRF and state tampering
  • Short-lived State: 10-minute expiry on state parameters
  • Public Client: No client secrets stored - uses PKCE instead
  • Encrypted Sessions: Cookie contents are encrypted and tamper-proof
  • Trusted Headers: User-provided X-VT-* headers are removed
  • CSRF Protection: Origin header validation for POST/PUT/DELETE requests
  • Secure Cookies: HttpOnly, Secure, SameSite=Lax flags

Known Limitations

  • userInfo endpoint: Currently may return null or incomplete data
    • This is a known issue with the Val Town OAuth server
    • User ID may show as "unknown" until this is resolved
  • No session rotation: Sessions are valid for 30 days without rotation
  • No server-side revocation: Sessions can't be revoked server-side (stateless design)

TODOs

  • Debug why userInfo returns null or incomplete data
  • Consider moving cache information from blob storage to sqlite for performance
  • Add optional session rotation support
  • Add helper function to extract full session data (including tokens) from cookies
FeaturesVersion controlCode intelligenceCLIMCP
Use cases
TeamsAI agentsSlackGTM
DocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareers
We’re hiring!
Brandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Open Source Pledge
Terms of usePrivacy policyAbuse contact
© 2025 Val Town, Inc.