Edit on val.town ↗

Access

You can limit access to a val to only your organization or particular people. This doesn’t require any code changes. It’s a setting, under the App access header on the Settings page of any val owned by an eligible organization.

Settings > Access

There are two independent settings for privacy in the list:

  1. Code access controls whether your val’s source code is visible.
  2. App access controls who can reach the val’s HTTP endpoints, on both val.run URLs and custom domains.

App access has two states:

  1. Anyone with the URL: Val Town doesn’t restrict visitors at all. You can still implement your own access controls in your val’s code.
  2. Restricted: only the organizations, users, invited email addresses, and allowed email domains you list can reach the val.

Note: Restricted access is available on vals owned by an organization on a Business account.

When a val is restricted, you can configure who is allowed to use it:

Visitors to a restricted val are sent to Val Town to sign in and then back to your val. Sessions last 30 days, after which they will re-authenticate, which is usually transparent and instant.

If an organization is downgraded to free and loses this feature, restricted vals will produce HTTP 402 errors until they are adjusted to be public or the organization is upgraded.

If your val relies on user identities, say for people creating content or commenting under their own names, you can read the viewer’s identity from the request. We inject a signed x-val-town-user header into each request, which you exchange with our API for a user ID and profile information.

Send the header value you received to the /v3/val/viewer endpoint, authenticated with the val’s own project-scoped API token. It returns the viewer’s public profile: id, username, bio, profile image, and profile URL. No email address or account tier is exposed.

export default async function (req: Request) {
  const identity = req.headers.get("x-val-town-user");
  if (!identity) return new Response("No viewer identity");

  const res = await fetch("https://api.val.town/v3/val/viewer", {
    headers: {
      "x-val-town-user": identity,
      Authorization: `Bearer ${Deno.env.get("valtown")}`,
    },
  });
  const viewer = await res.json();
  return Response.json(viewer);
}

Some details worth knowing:

Access works seamlessly for people visiting your val in a browser, but many vals need programmatic access too:

Those callers can’t complete a sign-in flow. For them, create a bypass token and include it with the request. Bypass tokens work and look much like API tokens, and can be sent either in the X-Val-Town-Access header or as a ?val_town_access= query parameter.

Bypass tokens start with vtba_, so they’re easy to detect. Other things to know:

You can create bypass tokens on the Settings page under App access, or via the API and the MCP server’s create_bypass_token tool.

Controlling val access is fully supported by our MCP server and plugin. Just ask your agent, and it will know how to set a val’s access to restricted.

Last updated