Skip to content

gate

The tunnel’s in-app AUTH GATE - Express middleware + login routes the AuthGatePlugin registers on the app’s OWN server via this.context.

The gate is MIDDLEWARE, not a reverse proxy - the app is the process, so there is nothing to forward to. It either short-circuits (401, or answers the open login routes) or calls next() to let the app’s real handlers run. It is the “stands in for AppKit auth” path: a portr caller authenticates with Better Auth OTP or a passkey, and on success the gate injects the identity headers AppKit reads.

WHICH TRAFFIC IS GATED - the Host header, not the socket. portr’s client forwards with Go’s httputil.NewSingleHostReverseProxy and a Director that PRESERVES the original Host, so tunnel requests arrive with Host: <subdomain>.<server> (the public domain). A local process hitting the app directly sends Host: 127.0.0.1:<port> / localhost. So ONLY requests whose Host matches the configured public domain are gated; the platform front door and any other local client pass through untouched. There is no portr-injected identifying header and no TCP/source-IP signal to use instead (the client dials the target over plain loopback).