access_mode = "accounts", the floo gateway puts a hosted sign-in flow in front of your app, validates each user’s session, and injects identity headers into every request before it reaches your code.
You write no auth code, login page, session store, or OAuth flow. Your app reads X-Floo-User-Email from the request headers.
Turn on sign-in
1. Set the access mode
Infloo.app.toml:
[auth] block sets the sign-in policy and branding.
2. Deploy
https://my-app-dev.getfloo.app (and the prod URL after promotion). Invited users sign in with their floo account through the hosted sign-in page, including Google and the other providers configured for floo.
3. Read the user from request headers
Every request that reaches your app carries the signed-in user:X-Floo-* header the browser sends before adding its own, so these values always come from the gateway. Examples for each major stack are in the Build with… guides.
Your app has per-user auth. The gateway redirects unauthenticated requests, manages the session cookie, and tells you who the user is on every request, with no change to your app code.
What gateway-managed auth gives you
Invite app users
Accounts-mode apps are invite-only. Invite a person from App → Access in the dashboard or from the CLI:floo apps invites lists pending invitations. Resending rotates the old link,
and revoking makes it unusable immediately. floo apps members lists active
app members with the IDs needed for role changes or removal. The org-level
Users page in the dashboard lists everyone with an active membership in
any of your apps.
App users do not use builder seats. To give someone access to floo itself,
see Team, roles, and API keys.
An organization member is not automatically an app user. The app’s creator
gets an explicit admin membership when the app is created; invite other
operators to the apps they should use.
Access modes
For program access, set
access = "api_key" on a route. See App API keys.
SAML or OIDC sign-in for app users is not available yet. Enterprise orgs can
require SSO for floo members and provision them with SCIM; see Team, roles, and API keys.
Per-environment overrides
[environments.<env>] access_mode wins over [app] access_mode for that environment, and each environment resolves on its own: prod never inherits dev’s override. The accepted keys are dev, prod, and preview; any other name, such as [environments.production], fails the deploy rather than being ignored. Common pattern: public in dev so iteration is fast, accounts in prod.
When a change applies
Each deploy freezes one mode per environment, resolved from[environments.<env>] access_mode, then [app] access_mode, then the
environment’s current mode. The target environment’s mode applies when that
deploy goes live, so a dev deploy never changes prod; a prod release copies
the map from the dev deploy it releases.
Loosening access, such as accounts to public or a looser access_policy,
applies like any other change, unless your org or app has an
approval policy that gates access broadening. Then
only an authenticated floo redeploy --rebuild by an org admin can loosen dev.
access_mode belongs under [app] or [environments.<env>]; preflight
rejects it inside [services.<name>].
Sign-in policy
[auth] access_policy accepts invite (the default), domain, and open.
Admission is invitation-only under all three: only people with an active app
membership get in, and no one is admitted by email domain or self-signup. See
[auth] for branding.
Where to change what
Reading the user in your app
The pattern is the same in every stack: read the request header./__floo/me, fetch the user as JSON
Client-side code can fetch the user object from /__floo/me:
401 if the session is missing or expired. The endpoint is on your app’s own host, so there is no CORS to configure.
/__floo/logout, sign out
/__floo/logout accepts POST and DELETE. Other methods (including GET) return 405 Method Not Allowed with Allow: POST, DELETE. On a successful POST/DELETE the gateway clears the __floo_session cookie, invalidates the session in floo’s session store, and returns 302 to the floo managed-auth login page. After signing back in, the user lands at the app’s root (/), not the page they signed out from.
Why no plain <a href="/__floo/logout"> link? The session cookie is SameSite=Lax, which still sends the cookie on cross-origin top-level GET navigation (a malicious link the user clicks, or a window.location redirect from another tab). A GET-served logout was reachable from any other site and could force a sign-out. POST and DELETE are not sent cross-origin under Lax under any condition, so restricting to those methods closes the vector.
Sign-out clears floo’s session, not the upstream identity provider. If the user signed in through an identity provider such as Google and that provider’s session is still active, the next visit will silently re-authenticate without a password prompt, exactly like browser SSO across other apps. To force a full re-login, the user has to sign out of the identity provider separately. (Single-Logout / federated sign-out is not yet supported.)
Form button (POST):
Caching signed-in responses
On a signed-in request, floo rewrites your app’sCache-Control so only the
user’s own browser can cache the response:
public,s-maxage, andproxy-revalidateare removed andprivateis added.- Browser directives such as
max-age,immutable, andno-cacheare kept. - A
no-storeresponse staysno-store. CDN-Cache-Control,Surrogate-Control, and other CDN-targeted cache headers are removed.
private on every response,
so a cached copy can never skip the IP check.
Local development
The floo gateway is not in the request path locally, so no identity headers reach your app unless you add them.Use floo dev --fixture-user
For accounts-mode apps, floo dev --fixture-user EMAIL starts a small in-process proxy in front of each service that injects the same X-Floo-User-* headers floo’s gateway adds in production:
X-Floo-User-Email, X-Floo-User-Id, X-Floo-User-Name, and X-Floo-User-Role exactly as in production. Use the raw URL for unauthenticated paths.
Optional flags fill in the rest of the fixture user (defaults shown):
The proxy runs only for apps with
access_mode = "accounts". With any other access mode, floo dev warns and skips the proxy.
Inject the headers yourself
For one-offcurl tests, scripts, or skipping the proxy:
process.env.NODE_ENV === "development" (or your stack’s equivalent).
Troubleshooting
Users see a login page on every request
The session cookie is not sticking. Check the app’s response headers: a successful login sets__floo_session on the app’s host. If the cookie is absent, a proxy between floo’s edge and the browser is stripping Set-Cookie, or the custom domain is misconfigured; run floo doctor accounts --app my-app to see the gateway state serving the app.
Identity headers are missing from requests
The app has not been redeployed sinceaccess_mode = "accounts" was set. Push (or floo redeploy --app my-app) to pick up the gateway routing change.
Users from outside my company can sign in
Admission is invitation-only under everyaccess_policy value: only people with an active app membership get in. List members with floo apps members --app my-app and remove anyone unexpected with floo apps member-remove.
I want users to land on a specific page after login
The gateway redirects to the original requested URL after sign-in, so link unauthenticated users straight to the deep link they wanted. To force a landing page, redirect from/ based on X-Floo-User-Email.
Build a stack-specific app
Stack journeys (Rails, Next.js, FastAPI, Django, Express) showing the full deploy + auth flow.
Team, roles, and API keys
Org members, roles, and floo API keys.
Custom domains
Put your auth-protected app on
app.yourcompany.com.