drift Docs
Start
What is Drift?
The tour, if you are new here.
Use cases
Whether Drift does your thing.
Getting started
Nothing to deployed, in one command.
Architecture
How a slice is put together.
What it costs
The free grant, four unit prices, two rules.
Build
Canvas
Static sites, same origin as your API.
Tools
Operate
Auth
Route gates, API keys and your account.
Security
Boundaries, sandboxing and hardening.
Troubleshooting
Error codes
What went wrong, and what to do about it.
Legal
Acceptable use
What a slice may not be used for.
Data processing
The DPA, and every sub-processor.

Edge The site gate

A deployed site is public the moment it lands. The site gate puts HTTP Basic auth in front of it: a visitor gets the browser's own password prompt, and without a username and password the gate accepts, never reaches the site. It is the wall for a site that is not ready to be found, kept off search engines and out of a forwarded link, rather than an authorization model: anyone holding a password reaches everything the gate fronts.

What it covers

Canvas paths, and only Canvas paths. Every site the slice hosts, at every route, sits behind the one gate; there is no way to gate one site and leave another open. A path under /api/ or /trigger/ is never asked for this credential, because both carry their own in the same Authorization header, and a gate there would collide with an app's Bearer tokens and API keys. Guard a Pulse with an auth block instead.

The gate runs after the address allowlist and after the rate limit, so a visitor guessing passwords spends the slice's per-minute budget like any other request, and a client the allowlist refuses never reaches the prompt.

Declaring it

Driftfile
edge {
  site_auth {
    realm = "Staging" # what the browser's password box says

    user "alice" {
      password = env("ALICE_PASS") # the NAME of an environment variable
    }

    user "bob" {
      password = env("BOB_PASS")
    }
  }
}

A password is never written in the file. The Driftfile is committed, so each password is env("NAME"), naming a variable that drift apply reads when it runs: from your shell, a --var NAME=value flag (--secret does the same), or the .env beside the Driftfile. A literal is refused, and the refusal never prints the value:

Driftfile:15:18: A secret is a reference: site_auth user "alice": password is write-only and must be written env("NAME"): a literal here would be a credential committed with this file

A variable that is unset or empty refuses the whole file before anything is sent, naming the user and the variable and never a value: edge.site_auth: the password for user "alice" is read from $ALICE_PASS, which is not set. Export it, pass --secret ALICE_PASS=..., or add it to the .env beside the Driftfile. The ... there is the CLI's own placeholder for the value.

Present, the block is the whole credential set: the users it names are exactly who can sign in. The apply says who that is, and who it shut out:

  ✓ site gate set: alice, bob can sign in
    removed: carol

Absent, the gate stays as it is, on or off. No declaration turns the gate off, because that is the one direction that exposes the site: delete the block and run drift slice auth disable, which asks first. drift plan shows the gate and each user: + site_auth when the gate would be turned on, + site_auth alice password from $ALICE_PASS for a user who would be added, site_auth alice present; password set again from $ALICE_PASS on apply (write-only, not compared) for one who stays, - site_auth carol removed for one who would be shut out (which drift apply asks you to agree to), and ! site_auth alice $ALICE_PASS is not set here: apply would refuse for a variable that is missing. The block is described in the Driftfile reference.

From the CLI

The commands act on the active slice, for a one-off change or a slice no Driftfile manages.

Command What it does
drift slice auth set --user <name> [--realm R]Turn the gate on for the users named, replacing every credential already set. Repeat --user for more than one.
drift slice auth set --user <name> --password-stdinThe same, reading one password per --user, in order, from stdin, for CI
drift slice auth listWhether the gate is on, its realm, and who can sign in
drift slice auth disableRemove the gate, after a confirmation

set prompts for each password with echo off. There is no --password flag, because the value would land in ps output and shell history.

Shell
$ drift slice auth set --user alice --user bob --realm Staging
Site gate enabled. alice, bob can sign in.
  Realm: Staging
  Visitors without the password now get a 401 instead of the site.
Shell
$ drift slice auth disable
This makes the site publicly reachable by anyone with the URL.
Remove the site gate? [y/N]

Answering y prints Site gate removed. The site is public again.; anything else prints Left as it was. and changes nothing. list prints No site gate. The site is public. for a slice without one.

What a visitor sees

Without a credential, or with a wrong one:

HTTP/1.1 401 Unauthorized
Content-Type: application/json
WWW-Authenticate: Basic realm="Staging"

{"error":"authentication required"}

The WWW-Authenticate header is what makes a browser draw its password box. A gate with no realm advertises Restricted. When the slice's Deed cannot be asked (it is restarting, or cannot read its own record), the answer is:

HTTP/1.1 503 Service Unavailable
Content-Type: application/json

{"error":"site authentication is unavailable"}

A gate whose checker is down stays shut. No failure on the way to Deed is ever turned into an admission.

Who checks the password

Edge decides, Deed verifies. The router decides that a Canvas request must carry a credential; whether the credential is good is the slice's own Deed to say.

  • set hashes before anything leaves the front door. The api bcrypts each password as it arrives, so the plaintext never travels further into the platform.
  • The digests live sealed in the slice. The record is pushed into the slice's Deed, which keeps it encrypted under the slice's own key, beside Vault, Link and Pocket. Once Deed holds it, Drift's control plane keeps only the gate's shape: whether it is on, the realm and the user names. It holds no digest.
  • The router asks; it never looks. For a visitor's credential, the router sends the name and password, in a request body, to the one route Deed serves on its gate port, POST /verify, and acts on the yes or no that comes back. Nothing else of Deed's is reachable on that port, so the router can ask the question without being able to read a digest, a Vault entry or a Pocket item.
  • A pass is remembered briefly; a failure never. A credential that cleared the gate is not asked about again for up to 60 seconds, so a browser resending it on every request costs Deed about one check a minute. A refusal is never remembered. One consequence: a user you remove can keep reaching the site for up to a minute.

A slice whose Deed cannot take the record yet (an older slice runtime, or one that was unreachable when you set the gate) keeps it in the control plane, and the router checks the digests there until a background pass, every five minutes, moves it into Deed. Either way the gate you set is the gate that is enforced.

Limits

Limit Value
Users1 to 32. A gate nobody can pass is refused.
Username1 to 64 characters, no colon (Basic auth splits on it) and no control characters; a Driftfile also refuses whitespace. Each name once.
PasswordAt least 12 characters and at most 72 bytes, the most bcrypt can hash. Unlike an account password, it is not screened against lists of breached passwords.
RealmAt most 64 characters, with no ", no \ and no control characters
ScopeSlice-wide, Canvas paths only