oauth
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.
Viewing readonly version of main branch: v134View latest version
A middleware library for adding OAuth authentication to Val Town vals using the Val Town OAuth provider.
- 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
- Hono Middleware: Drop-in middleware for Hono apps
/** @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"]
// });
The middleware automatically handles these routes:
/auth/login- Initiates the OAuth flow, redirects to Val Town authorization/auth/callback- Handles the OAuth callback and exchanges code for tokens/auth/logout- Logs out the user (not yet implemented)
Once session management is implemented, authenticated requests will include:
X-VT-User-Id- The Val Town user IDX-VT-User-Email- The user's email addressX-VT-User-Name- The user's display name
Optional:
OAUTH_STATE_ENCRYPTION_KEY- Secret key for encrypting OAuth state- 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
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
Hono middleware that:
- Intercepts auth-related routes (
/auth/*) - Manages the OAuth authorization flow
- Will handle session creation/validation (in progress)
Demo application showing how to use the middleware
- 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
⚠️ Session management is not yet implemented. The callback currently returns JSON with tokens but doesn't:
- Create a session
- Set session cookies
- Persist authentication across requests
- Populate user headers
See the TODOs section below for planned improvements.
- Implement session management - Store and validate user sessions
- Write session code in
session.ts - Set user headers (
X-VT-User-Id,X-VT-User-Email,X-VT-User-Name) - Ensure headers are trusted (delete any user-provided headers before setting them)
- Consider using encrypted session cookies (using the same encryption key) vs database storage
- Inspiration: https://www.val.town/x/stevekrouse/luciaMagicLinkStarter/code/backend/database/sessions.ts
- Write session code in
- Implement
/auth/logout- Clear session and redirect - Debug why userInfo returns
null(which can be seen after testing) - Consider moving cache information from blob storage to sqlite for performance.