Skip to content
← Blog

How do I add sign-in to an internal app without writing auth code?

Put sign-in in front of the app instead of inside it. On floo, one line in floo.app.toml makes an app invite-only, and your code reads the signed-in person from a request header.

floo team

TL;DR

Move sign-in out of the app and into the layer in front of it. On floo, access_mode = "accounts" in floo.app.toml puts a hosted, invite-only sign-in in front of every request, and your code reads who is signed in from a header. There is no login page, session store, or email provider to build.

  • Auth inside the app is the expensive path. Supabase's official Next.js template generates 11 auth files, about 448 lines, before the app is invite-only.
  • A gateway in front of the app is the cheap path. The question is who the gateway admits, and whether your code learns who they are.
  • On floo, access is explicit. Only people invited to that app get in, and removing someone revokes their sessions at once.
  • The trade-off: invited people sign in with a floo account, and SAML or OIDC for app users is not available yet.

Most internal software starts the same way. Your agent builds something useful in an afternoon, such as a page that shows the numbers the team argues about, or a form that replaces a spreadsheet. Then someone asks to share it, and the next request is "make sure only we can see it." That request can turn a small app into an auth project.

Why does sign-in take longer than the app?

Because sign-in written inside the app is a system of its own: a login page, a session cookie, token refresh, password reset, an invite email, and a way to remove someone. Each piece is easy for an agent to write and hard to get right. When we traced the official with-supabase Next.js template on October 22, 2026, it generated 11 auth files, about 448 lines, and still needed sign-ups disabled, an invite script holding the secret key, and a custom SMTP provider before it could invite people outside the Supabase org. The full trace is here.

None of that is the reason the app exists.

What is the alternative?

Put a gateway in front of the app that does sign-in for it. The app never sees an anonymous request, and it never stores a password. Three questions decide whether a gateway is enough:

  1. Who can it admit? A specific list of people, or anyone with an account on some platform?
  2. Does your code learn who the person is? An app that shows "my tasks" or records who approved something needs the identity, not just a locked door.
  3. Can a program still get in? If your agent also uses the app, a gate that blocks every machine caller forces you to make the app public again.

How does floo do it?

One line of config:

[app]
name = "stock-room"
access_mode = "accounts"

After the next push, the floo gateway intercepts every request to the app. A person without a session goes to the hosted sign-in page. A person with a session but no membership in this app is not admitted. Everyone else reaches your code with four headers attached:

X-Floo-User-Email: jane@acme.com
X-Floo-User-Id:    01HQK4...
X-Floo-User-Name:  Jane Doe
X-Floo-User-Role:  member

Reading the user is reading a header, in any language. Client-side code can call /__floo/me on the app's own host for the same fields as JSON, and a sign-out button posts to /__floo/logout.

Access is managed per app. floo apps invite jane@acme.com --role member sends the invitation, and floo apps members lists who has access. App users do not use builder seats and get no access to floo itself, so inviting the whole office to one dashboard does not hand anyone your deploys. Removing a member revokes their sessions immediately, and changing a role signs out sessions that carry the old role.

Your agent can do all of this. The config lives in git, the commands support --json, and the same operations are in the floo HTTP API.

What about local development?

The gateway is not in front of your laptop, so floo dev --fixture-user you@example.com starts a small proxy that adds the same X-Floo-User-* headers. The app behaves the same locally as it does deployed, and there is no "if development, skip auth" branch to forget.

You can also keep a dev environment public while you iterate and make production invite-only:

[app]
name = "stock-room"
access_mode = "accounts"

[environments.dev]
access_mode = "public"

What about the agent that uses the app?

An invite-only app still needs to accept calls from programs, such as your agent updating rows or a script pulling a report. On floo you declare which routes accept an API key and mint a key for a named consumer. People keep signing in, programs present a key that works only on those routes, and revoking the key signs no one out. How to give your agent its own key.

How do the other approaches compare?

From each vendor's docs, read between October 22 and October 29, 2026:

ApproachWho it admitsIdentity in your codePrograms
Write it in the app (for example Supabase Auth)Whoever your code allowsYes, from your session codeYours to build
Vercel AuthenticationVercel users granted access to the team or project, on every planNot described in its docsA bypass secret that covers the whole project
Vercel PassportPeople in your own identity provider, such as Okta or Entra ID; Enterprise plan onlyYes, a token header and an SDKNot covered here
Cloudflare AccessInvited emails, with a one-time codeYes, a signed tokenService tokens per caller
floo access_mode = "accounts"Only people invited to that appYes, X-Floo-User-* headersScoped keys per consumer on declared routes

Vercel Passport is the right answer if you are on Vercel Enterprise and your team already lives in Okta or Entra ID. Cloudflare Access is a strong option if your app already runs on Cloudflare and SQLite is enough for its data. floo puts the gate, Postgres, scheduled jobs, and program keys in the same app config on every plan.

What are the limits?

  • Invited people sign in with a floo account. They can use Google through the hosted sign-in page.
  • SAML or OIDC sign-in for app users is not available yet. Enterprise orgs can require SSO for sign-in to floo itself.
  • Admission is invitation-only. floo does not admit people by email domain or self-signup.

If those fit, sign-in stops being a project. Set one line, push, and invite the team. The app sign-in guide has the full reference.

Sources

Frequently asked questions

How do I make a web app only my team can open?

Put an authenticating gateway in front of it. On floo, set access_mode = "accounts" in floo.app.toml, push, and invite people with floo apps invite. Anyone without an app membership is sent to sign in and is not admitted.

Does my app need a login page or session code?

Not on floo. The gateway runs the sign-in flow and the session cookie, then adds X-Floo-User-Email, X-Floo-User-Id, X-Floo-User-Name, and X-Floo-User-Role to every request that reaches your code.

What happens when someone leaves the team?

Remove their app membership with floo apps member-remove or from App, then Access in the dashboard. floo revokes their app sessions immediately.

Can teammates sign in with Google?

Yes. Invited people sign in to a floo account through the hosted sign-in page, which includes Google. SAML or OIDC sign-in for app users is not available yet.

Can I keep sign-in off while I build and turn it on for production?

Yes. Set access_mode per environment, for example public under [environments.dev] and accounts under [app] or [environments.prod]. Each environment resolves on its own.

Build AI systems.

Supercharge your agent by letting it build and run software.

Get an API key
Usage-based pricing. See plans →