A single binary that serves a directory of static files behind an OpenID Connect login. Made for internal sites such as a Storybook, docs, or coverage reports behind Google Workspace or any OIDC issuer.
docker run --rm -p 3000:3000 -v "$PWD/site:/srv/site:ro" \
-e GATELET_PUBLIC_URL=https://storybook.example.com \
-e GATELET_SECRET="$(openssl rand -hex 32)" \
-e GATELET_CLIENT_ID=... \
-e GATELET_CLIENT_SECRET=... \
-e GATELET_ALLOWED_DOMAINS=example.com \
ghcr.io/tunnelworks/gateletOr build it with cargo build --release and run gatelet <DIR>. Register <GATELET_PUBLIC_URL>/.auth/callback
as the redirect URI of your OAuth client; for Google Workspace, set the client's audience to Internal.
Every flag also reads the environment variable in the table:
| Flag | Variable | Default | Meaning |
|---|---|---|---|
<DIR> |
required | Directory to serve | |
--public-url |
GATELET_PUBLIC_URL |
required | Origin browsers use to reach the gate |
--secret |
GATELET_SECRET |
required | Cookie key material, 32 bytes or more |
--client-id |
GATELET_CLIENT_ID |
required | OAuth client id |
--client-secret |
GATELET_CLIENT_SECRET |
required | OAuth client secret |
--provider |
GATELET_PROVIDER |
google |
google or oidc |
--issuer |
GATELET_ISSUER |
Google's | Issuer URL for discovery (oidc) |
--allowed-domains |
GATELET_ALLOWED_DOMAINS |
Comma-separated organization domains | |
--allowed-emails |
GATELET_ALLOWED_EMAILS |
Comma-separated email addresses | |
--session-ttl |
GATELET_SESSION_TTL |
7d |
Idle window before a session expires |
--session-max-age |
GATELET_SESSION_MAX_AGE |
30d |
Absolute session limit |
--health-path |
GATELET_HEALTH_PATH |
/up |
Public health check path |
--bind-addr |
GATELET_BIND_ADDR |
0.0.0.0:3000 |
Listen address |
Set at least one of the allow lists. With google, the domain rule checks the hd claim, so consumer accounts
never match. Sessions are encrypted cookies that renew while the site is in use; changing the secret signs everyone
out.
Storybook composition probes index.json with Accept: application/json; without a session gatelet answers
200 { "loginUrl": "..." }, which makes Storybook show its sign-in prompt and complete the login in a popup. The
composing Storybook must share the gate's origin, because gatelet sends neither CORS headers nor SameSite=None
cookies.
Apache-2.0