Skip to Content
Teitunnel

Guides

Require a login

Protect a Cloudflare Tunnel route with a login using Cloudflare Access: a one-time code by email, or GitHub or Google sign-in, for the people, email domains or GitHub teams you list, set up in one step.

A route is public by default: anyone with the address reaches your app. Require a login puts Cloudflare's sign-in page in front of it, so only the people you list get through. Cloudflare checks the login at its edge, before a single request reaches your computer.

Use it for anything that isn't meant for the whole internet: an admin panel, a staging site, Home Assistant, a tool you share with a few colleagues. For machines (CI jobs, scripts) that need to pass the same login, add a service token.

What you need

  • Cloudflare Zero Trust, set up once on the account. It's free for up to 50 users. If the account has never used it, Teitunnel shows a Set up Cloudflare Zero Trust card instead of the form: choose Open Zero Trust, choose a team name, pick the Free plan when asked, then come back and choose Try Again. Only the dashboard can set it up.
  • Two account permissions on the credential: Access: Apps and Policies · Edit and Access: Organizations, Identity Providers, and Groups · Edit (the second only to add the one-time code login when the account has no login method yet). Tokens created from Teitunnel's link and OAuth sign-in include them.

Turn it on in the app

In Routes, choose Edit route on the route (or New route for a new one).

Open Advanced and turn on Require a login.

Under Who can sign in, list:

  • an email address, like team@yourhost.com, to let that person in;
  • @yourhost.com to let in everyone with an address at that domain;
  • github:teispace to let in the members of a GitHub organization, or github:teispace/Developers for one of its teams (its name as GitHub shows it).

Under Log in with, keep Any Method, or choose GitHub or Google so people can only log in that way (see GitHub and Google). Paths that skip the login lets webhook senders through (see below).

New Route, Advanced: Require a login turned on, Who can sign in with an email address and a domain, Log in with Any Method, GitHub or Google, and Paths that skip the login

Choose Review, read the plan, and choose Save (Add Route for a new route).

Visitors then see Cloudflare's sign-in page first. By default they get a one-time code by email; any other login methods the account has (Google, GitHub, a company identity provider) are offered too. A sign-in lasts 24 hours.

The same login works on a share on your domain and on a Snapshot (People I choose).

GitHub and Google

A login can use a GitHub or Google login method of the account instead of an emailed code:

  • GitHub teams: github:teispace lets in the members of the organization, and github:teispace/Developers the members of one team. Visitors go straight to GitHub's sign-in, and Cloudflare checks the membership when they come back.
  • Google: choose Log in with ▸ Google and list @yourhost.com to let in everyone who signs in with a Google (or Google Workspace) account at that domain.

The login method itself is set up once, in the Cloudflare dashboard, because that's where its client secret goes: Zero Trust ▸ Integrations ▸ Identity providers ▸ Add, then GitHub or Google, following Cloudflare's steps (GitHub, Google). Use Test there to check it. If the account doesn't have one yet, the plan stops with "This account has no GitHub login method yet" and Open Identity Providers.

Teitunnel limits the route's login to that method (the Access application's allowed login methods) and names its policy Allowed people · GitHub or Allowed people · Google. If the login method is later replaced in the dashboard, the next change to the route follows the new one.

Let webhooks through

Webhook senders (Stripe, GitHub, Slack…) and other machines can't sign in. Under Paths that skip the login, list the paths they call, such as /webhooks: everything under them is reachable without a login, and the rest of the route still asks for one. Check their signatures in your app (the inspector shows whether they're valid). For machines you control, a service token is the safer choice: it lets only them through.

From the terminal

# A new route that only your team can open
teitunnel route add admin.yourhost.com 3000 --allow team@yourhost.com --allow @yourhost.com

# A share on your domain with a login, for as long as the command runs
teitunnel share 5173 --on review.yourhost.com --allow @yourhost.com

# A Snapshot behind a login
teitunnel snapshot publish ./dist --on preview.yourhost.com --allow @yourhost.com

# Only a GitHub team, logging in with GitHub
teitunnel route add staging.yourhost.com 3000 --allow github:teispace/Developers

# Everyone at the domain, logging in with Google
teitunnel route add docs.yourhost.com 4000 --allow @yourhost.com --sign-in google

--allow is repeatable and takes an email address, @domain, or github:org / github:org/team. --sign-in github|google|any says how people log in (a GitHub entry implies github). --skip-login /webhooks (repeatable) lets webhooks reach that path without a login. route add creates new routes only ("… is already routed. Edit that route instead."): change who can sign in to an existing route in the app, or in its project file.

If a permission is missing

An older token, or one made by hand, may lack the Access permissions. Then turning on Require a login shows The token needs 2 more permissions instead of failing:

  1. Open API Tokens takes you to your tokens in the Cloudflare dashboard.
  2. Choose Edit next to the token you connected (Cloudflare names it "Teitunnel" if you used the link), add the permissions, then Continue to Summary and Update Token.
  3. Switch back to Teitunnel. It checks again by itself and the form continues where you left it. The token doesn't change, so there's nothing to paste.

If you'd rather not edit the token, Use a New Token Instead and Create Token open a token with every permission Teitunnel uses; paste it and it replaces the account's credential. Accounts connected with a cloudflared login can't gain these permissions; connect them with an API token instead.

What happens on Cloudflare

Like every change, you review the plan before anything happens:

  • Add One-time PIN as a login method: only when the account has none.
  • Require a login for admin.yourhost.com (team@yourhost.com, anyone at @yourhost.com): an Access application named Teitunnel · admin.yourhost.com with a reusable policy allowing the people you listed. It's created before the route goes live, so the route is never reachable without a login.
  • Let only … into admin.yourhost.com: changing who can sign in updates the policy.
  • Let everyone reach admin.yourhost.com/webhooks without a login (webhooks): one more application, Teitunnel · admin.yourhost.com/webhooks, whose policy lets everyone through (Access applies the most specific path). It comes and goes with the login.
  • Remove the login from admin.yourhost.com: turning the login off, or removing the route, deletes the application once the route is gone (and Teitunnel's policy, unless another application uses it).

Undo in Activity puts the previous state back. Teitunnel changes only applications it created. If a hostname is already protected by an application made elsewhere, the plan stops ("admin.yourhost.com is already protected by an Access application Teitunnel didn't create. Change who can sign in there, in the Cloudflare dashboard.").

A route with a path (for example /admin) protects that path. Access matches plain paths, so a path pattern like ^/(a|b) can't have a login; use one route per path, or protect the whole hostname.

Checking a protected route

Test reports Works · asks for a login when Cloudflare answers with its sign-in page, and the review shows "Protected by a login: Cloudflare asks visitors to sign in before they reach your app." That proves the hostname is on Cloudflare and protected; the app behind the login isn't reached, because the check can't sign in. Uptime checks count a login page as up too.

Limits and costs

Cloudflare Zero Trust is free for up to 50 users. Beyond that it's a paid Cloudflare plan. Teitunnel adds nothing on top.

Troubleshooting

Edit on GitHub

Last updated on

On this page