Skip to main content
floo manages user authentication for your deployed apps. When you set 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. No login pages. No session storage. No OAuth flow. Your app reads X-Floo-User-Email from the request headers and renders a personalized response. That’s the whole integration.

Quickstart

Three steps from a deployed app to per-user sign-in.

1. Set the access mode

In floo.app.toml:
That’s the entire auth config. There is no [auth] section to add, no callback URLs to register, no client ID to provision.

2. Deploy

When the deploy completes, every request to https://my-app-dev.on.getfloo.com (and the prod URL after promotion) is intercepted by the floo gateway. Invited users sign in with their floo account through the hosted WorkOS page, including Google and the other providers configured for floo.

3. Read the user from request headers

Every request that reaches your app’s container has the signed-in user attached:
Read them like any other header. 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. Your app code did not change to make this work.

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:
The recipient creates or reuses a floo account with that email, then accepts the app membership. Their account can use only the apps they were explicitly invited to; it does not grant dashboard, organization, deployment, billing, or platform API-key access. Use floo apps invites --app my-app to inspect pending invitations. Resending rotates the old link, and revoking makes it unusable immediately. Use floo apps members --app my-app to list active app members and copy the IDs needed for role changes or removal. An organization member is not automatically an app user. Invite operators to the apps they should use, including the app creator’s explicit admin membership.

Access modes

Enterprise SSO (SAML/OIDC) is handled as a sales-assisted setup rather than a self-serve access_modecontact sales if your team needs it.

Per-environment overrides

The override wins for that environment. Common pattern: public in dev so iteration is fast, accounts in prod.

Password-protected apps

For a single shared password (no user accounts), set the access mode in floo.app.toml:
The platform generates the shared password automatically on the next deploy. Retrieve it with:
Anyone with the password gets in; there is no per-user identity, and identity headers are not injected.

Reading the user in your app

The pattern is the same in every stack: read the request header.
For full stack-specific examples, see the Build with… guides.

/__floo/me — fetch the user as JSON

For client-side code that needs the user object, hit /__floo/me from the browser:
Returns 401 if the session is missing or expired. The endpoint is on your app’s own host, so 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 the user signs back in they land at the app’s root (/) — not the page they were on when they signed out. 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 originally signed in via WorkOS and their WorkOS 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 IdP separately. (Single-Logout / federated sign-out is not yet supported.) Form button (POST):
Rails / Turbo:
or with Turbo’s data attribute on a link:
JavaScript fetch:

Local development

The floo gateway isn’t in the request path locally, so by default no identity headers reach your app. You have two options.

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:
Output shows two URLs per service — the raw service URL and the auth-proxied URL:
Hit the auth-proxied URL when you want to test signed-in flows — your app sees X-Floo-User-Email, X-Floo-User-Id, X-Floo-User-Name, and X-Floo-User-Role exactly as it would in production. Hit the raw URL for unauthenticated paths or quick checks. Optional flags fill in the rest of the fixture user (defaults shown): The proxy only runs for apps with access_mode = "accounts" — if you pass --fixture-user against any other access mode, floo dev warns and skips the proxy.

Inject the headers yourself

For one-off curl testing, scripts, or stacks where you’d rather skip the proxy entirely:
Or wrap your header-reading helper to fall back to a fixture user when process.env.NODE_ENV === "development" (or your stack’s equivalent).

Troubleshooting

Users see a login page on every request

The session cookie isn’t sticking. Most likely your app sits behind a TLS-terminating proxy that strips Set-Cookie headers, or you’ve misconfigured a custom domain. Check the app’s response headers — a successful login sets __floo_session on the app’s host.

Identity headers are missing from requests

The app probably wasn’t redeployed after setting access_mode = "accounts". Push (or floo redeploy --app my-app) to pick up the gateway routing change.

Users from outside my company can sign in

You haven’t configured an access policy. Set a domain allowlist in the dashboard or in floo.app.toml under [auth].access_policy.

I want users to land on a specific page after login

The gateway redirects to the original requested URL after sign-in — so just link unauthenticated users to the deep link they wanted, and the gateway does the right thing. 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 Access

Org membership, app access policies, and password-protected apps.

Internal Tools

Why managed auth is the right answer for internal tools — and how a domain allowlist gives you a per-team app in one config change.

Custom Domains

Put your auth-protected app on app.yourcompany.com.