Skip to content
Docs

Accounts and sign-in

Owners (people who publish) sign in with an emailed six-digit code or with Google. There are no passwords. Signing in gives the browser or the agent an API key; an owner can name, list and revoke keys, and “Sign out everywhere” replaces every key and disconnects every AI app. Each new sign-in sends an alert email (owners can turn it off). A sign-in email change is confirmed from both addresses, and the old address gets an undo link. A key can be deploy-only (for CI: create, update, roll back and list sites), may carry a fixed expiry, and stops working after KEY_IDLE_EXPIRY_DAYS unused.

AI apps connect over the connector at /mcp with OAuth: the person signs in once in the window the app opens, and the app keeps a short access token it refreshes.

Visitors to a site on its own address can sign in with Google or an emailed code, so what they save is theirs and private lists stay private. One sign-in covers one site.

Email codes need email set up; Google needs an OAuth client whose redirect URI is <PUBLIC_BASE_URL>/v1/auth/oauth/google/callback. With neither, only the admin key signs in.

Setting Default Allowed What it does
SIGNIN_CODE_TTL_MINUTES 15 5–60 minutes How long an emailed sign-in code (and link) or email-change code works. Security-sensitive.
MAX_KEYS_PER_ACCOUNT 50 1–1000 keys API keys one account may create from the Keys panel.
KEY_IDLE_EXPIRY_DAYS 180 0–3650 days; 0 = never An API key unused this long stops working (counted from its last use, or its creation). 0: keys work until revoked. Security-sensitive.
HANDLE_RENAME_EVERY_DAYS 30 7–365 days Once something is published, how often an account may change its handle.
EMAIL_CHANGE_UNDO_DAYS 7 1–90 days How long the undo link sent to the old address after a sign-in email change works. Security-sensitive.
SHOWCASE_BIO_MAX_LENGTH 280 1–2000 characters Maximum plain-text bio length on the public personal showcase (hosted and small-box), in characters.
VISITOR_SESSION_DAYS 30 1–365 days How long a visitor stays signed in on a site’s own address, however active. Security-sensitive.
VISITOR_SESSION_IDLE_DAYS 14 1–365 days How long a visitor sign-in lasts unused. Not longer than VISITOR_SESSION_DAYS. Security-sensitive.
OAUTH_ACCESS_TTL_MINUTES 60 5–1440 minutes How long an AI app’s access token works before it refreshes. Security-sensitive.
OAUTH_REFRESH_TTL_DAYS 90 1–365 days How long an AI app stays connected without being used. Security-sensitive.
OAUTH_UNUSED_CLIENT_DAYS 30 1–365 days An AI app registration that never connected, or went unused, is removed after this many days.
RATE_LIMIT_SIGNIN_IP 20,5s stricter freely; loosest 80,1.25s Sign-in and email-change requests per address. Security-sensitive.
RATE_LIMIT_SIGNIN_EMAIL 5,50s stricter freely; loosest 20,12.5s Sign-in codes sent to one email address. Security-sensitive.
RATE_LIMIT_VISITOR_OAUTH 20,5s stricter freely; loosest 80,1.25s Visitor Google sign-ins per address. Security-sensitive.
RATE_LIMIT_VISITOR_AUTH 20,5s stricter freely; loosest 80,1.25s Visitor email-code sign-ins per address. Security-sensitive.
RATE_LIMIT_VISITOR 20,5s stricter freely; loosest 80,1.25s Finishing a visitor sign-in and signing out, per address. Security-sensitive.
RATE_LIMIT_HANDLE_CHECK 30,2s any (warns past 10× looser) Address availability checks while someone types a handle (GET /v1/handles/check), per address.
RATE_LIMIT_OAUTH_REGISTER 10,6m stricter freely; loosest 40,1m30s AI app registrations on the connector, per address. Security-sensitive.
RATE_LIMIT_OAUTH_AUTHORIZE 30,2s stricter freely; loosest 120,500ms AI app sign-in requests on the connector, per address. Security-sensitive.
RATE_LIMIT_OAUTH_TOKEN 30,2s stricter freely; loosest 120,500ms AI app token requests on the connector, per address. Security-sensitive.
ADMIN_API_KEY none secret The admin’s key. install.sh generates it and shows it once. Required. Security-sensitive.
GOOGLE_OAUTH_CLIENT_ID none text Google sign-in for owners and visitors: the OAuth client ID. Set with the secret, or neither.
GOOGLE_OAUTH_CLIENT_SECRET none secret Google sign-in: the OAuth client secret. Security-sensitive.
GITHUB_OAUTH_CLIENT_ID none text An optional second visitor sign-in provider: its OAuth client ID. Set with the secret, or neither.
GITHUB_OAUTH_CLIENT_SECRET none secret The second provider’s OAuth client secret. Security-sensitive.
OIDC_ISSUER none text Company sign-in: the identity provider’s issuer URL (https). Setting issuer, client id and secret together turns it on. Redirect URI: <PUBLIC_BASE_URL>/v1/auth/oauth/oidc/callback.
OIDC_CLIENT_ID none text Company sign-in: the OAuth client id registered at the identity provider.
OIDC_CLIENT_SECRET none secret Company sign-in: the client secret. Security-sensitive.
ALLOWED_EMAIL_DOMAINS none text Comma-separated email domains company sign-in accepts, e.g. example.com,example.co.uk. Sign-in from another domain is refused. Required when OIDC_ISSUER is Google (https://accounts.google.com).
OIDC_LABEL your company account text Names the company sign-in button: “Sign in with <label>”.
OIDC_INSECURE_ALLOWED false true / false true permits a plain-http OIDC_ISSUER. Local testing only. Security-sensitive.
PASSWORD_SIGNIN off on / off on enables username/password accounts on this install. Off on the hosted services.
PASSWORD_SELF_SIGNUP on on / off When password sign-in is on, on lets people create accounts; off allows only admin-created accounts.
EMAIL_SIGNIN on on / off off turns email-code sign-in off everywhere (account, connector, team-site visitors): refused at startup unless company or password sign-in is configured.
REVIEW_ACCOUNT_EMAIL none text A plugin reviewer’s account that may sign in with a password on the connector. Set with the hash, or neither.
REVIEW_ACCOUNT_PASSWORD_HASH none secret That reviewer account’s password hash. Security-sensitive.
SIGNUP_BLOCKED_COUNTRIES none text ISO-3166 alpha-2 country codes (comma-separated) that may not sign in or sign up (email-code or OAuth), resolved locally (GEOIP_DIR), never sent to a third party. An API key keeps working from anywhere (that is not a sign-in); an unresolved country is always allowed. Empty: off.

The sign-in rate limits can be made stricter freely, but at most four times looser than the default; anything looser stops the server at startup.

Recipes

Stricter sign-in.

SIGNIN_CODE_TTL_MINUTES=5
RATE_LIMIT_SIGNIN_IP=10,10s
RATE_LIMIT_SIGNIN_EMAIL=3,2m
VISITOR_SESSION_DAYS=7
VISITOR_SESSION_IDLE_DAYS=2
OAUTH_REFRESH_TTL_DAYS=30

Google sign-in only on a small box. Create an OAuth client (type “Web application”) with the redirect URI above, set GOOGLE_OAUTH_CLIENT_ID and GOOGLE_OAUTH_CLIENT_SECRET, and leave RESEND_API_KEY empty.

Key and session behavior

POST /v1/me/keys returns 409 key_limit at MAX_KEYS_PER_ACCOUNT; sign-in keys are not refused. Idle keys return 401 key_expired_idle, asking for a new key. For keys that predate idle expiry, the idle clock starts on the day it shipped. A Keys-panel key may also carry a fixed expiry (expires_in_days). Lowering KEY_IDLE_EXPIRY_DAYS applies immediately to every key, including ones already unused beyond the new limit. Expired keys (idle or fixed expiry) do not count toward the key cap and are deleted 30 days after expiry.

A handle change before HANDLE_RENAME_EVERY_DAYS returns 429 with next_change_after. VISITOR_SESSION_DAYS also sets the session cookie’s max age. Each use slides the idle expiry, never beyond the absolute lifetime. Each OAuth refresh issues a new refresh token.

Setting only one Google OAuth credential is treated as off. Country sign-in restrictions apply to both new and existing accounts. The plugin reviewer password flow is implemented in internal/handler/reviewer.go. The admin is a real account, upserted from ADMIN_API_KEY at boot.