Skip to main content
MigrationVal Town

Migrate Val Town access control

Keep private apps private on Easel.

On Val Town, who could read a val's code was separate from who could call it. On Easel, production URLs are public, so an app that limited who could call it checks access in its own code.

On Val TownOn Easel
Private codeA private repository
App access restricted to users or email domainsSign-in in your app, such as Better Auth, allowing the same people
Bypass tokens (X-Val-Town-Access)A secret your app checks, as below
Val Town sign-in (x-val-town-user)Your app's own sign-in

Check a token

For scripts and services that called a restricted val, compare a bearer token with a secret from the environment:

lib/require-token.ts
import { timingSafeEqual } from "node:crypto";

export function hasValidToken(request: Request) {
  const expected = process.env.API_TOKEN;
  const header = request.headers.get("authorization") ?? "";
  if (!expected || !header.startsWith("Bearer ")) return false;

  const given = Buffer.from(header.slice("Bearer ".length));
  const wanted = Buffer.from(expected);
  return given.length === wanted.length && timingSafeEqual(given, wanted);
}

Mark private responses Cache-Control: private, no-store so the CDN never caches them.

Protect previews

Previews run your code and can reach your data. Turn on deployment protection in Project settings → Security so visitors must sign in to your workspace to open them.

Verify

Request private pages and APIs signed out, signed in, and with a wrong token, and check that only allowed requests succeed.

Back to the feature list.