FlowPrime Subscribe - $99/mo
Back to FlowPrime
Identity

Two flags decide everything. Tick them.

A login and a customer workspace are two separate births on FlowPrime, and two flags on your product decide each one: whether a sign-up form exists, and what a login is worth once somebody has it. Tick a pair and the panel draws the map, what that shape gains and costs you, the sign-in screen it produces, and the first day of a new customer.

The words on this page
Login
One person, one e-mail, one password, across every product built on FlowPrime.
Token
What your app is handed on every request: a signed statement of who they are and which one company they act for. It cannot be edited, and it can never name two.
Customer
Anyone who signs into your product, your own team included when they use it rather than administer it.
Your workspace
What you buy from FlowPrime: your products, domains, branding, Stripe connection and staff. Every customer below shares it.
Customer workspace
One buying company inside your product: its own seats, its own plan with you, its own data. A token names exactly one and can never name two.
Grant
A promise of a company, written against an e-mail the moment they pay or verify, and cashed in at their first sign-in. The only way a company is ever created.
Seat
A person’s place in a company. It comes from an invitation or a purchase, never from filling in a form.
Owner and member
The owner’s seat holds the plan and the bill. A member is a seated teammate.
Consent
Nobody joins a company silently. An invitation becomes a seat when the person accepts it, not when you send it.
Clientele
A login with its own records but no company and no seat: your customers rather than your tenants.
Role
What a seat may do inside your app. Your app decides that; FlowPrime decides who holds a seat.
Team page
The hosted screen listing a company’s seats. Its owner runs it, not you, and it is the access list your app enforces.
About your customers
Who may create a customer login here?

The first of two flags on your product: whether a sign-up form exists at all. Your own team’s admin access is a different surface, and is not on this page.

What does a customer login get?

One question decides this: does more than one person ever need to see the same records? If yes, they need a company of their own. If never, they do not. Your own team, when they use the product rather than administer it, are customers here too.

a workspace of their own inside the one you run
How do they prove who they are?

E-mail and password always. These ride on top.

Inside a customer company
Teams inside a customer?

Who is in is ours to keep. What they may do is yours.

Who else may come in?

Never without a seat, and never under somebody else’s name.

A question?

Ask about this shape.

Leave your e-mail and the question. The dials you have ticked travel with it, so the answer is about the exact setup on your screen.

Goes straight to the people who built this, not to a mailing list.

Two levels

Your workspace, and the customer workspaces inside it.

The word does two jobs on this site, so here it is drawn. The outer box is what you buy from FlowPrime. The inner boxes are your customers. Everything in the outer box is yours and shared by every customer; nothing in an inner box is reachable from another.

YOUR WORKSPACE one FlowPrime subscription, one bill Every product you register Your domains and TLS Your branding everywhere Your Stripe connection Your own staff CUSTOMER WORKSPACES Acme Imports their seats, their plan, their data Beta Trading their seats, their plan, their data Gamma Logistics their seats, their plan, their data A customer workspace gets no domain, no branding and no Stripe account of its own. Those are yours, and every customer shares them.
AND IT NESTS Your customer can buy a workspace of their own.

Nothing stops them, and no plumbing is missing. Everyone who signs into your product already holds a platform identity, so buying FlowPrime authenticates the login they have rather than minting a second one. A workspace is provisioned with them as its owner, carrying its own products, domains, branding and Stripe connection, and their place inside yours is untouched: the subscription only adds rows. The dashboard then lists both, and one password opens either.

What they do not get is any reach into yours. Owning a workspace grants nothing inside somebody else’s, being your customer grants nothing inside theirs, and no token can carry both at once. Your other customers, your keys and your data stay exactly where they are.

One person, several hats

One login everywhere. Never two hats at once.

A person has one e-mail, one password and one identity across every product built on FlowPrime. Inside your product they wear exactly one hat per login: the owner of a company, a member of somebody else’s, or a customer of yours. The token that reaches your app carries that one hat and nothing else.

YOU, THE BUILDER You one e-mail, one password signs in once FlowPrime dashboard your organization, your products opens Your product’s console the staff hat YOUR CUSTOMER Helena the same kind of login opens your app Her company owner seat, her plan A client’s company member seat, their plan one at a time, by a switcher in your header The database knows all of her hats. A token shows one, chosen by which door she came through. Her staff hat, if she has one, never appears inside your app.
How a login is born

Every screen on the way in. You build none of them.

A login on your product is born by paying, by signing up, or by being invited. Every screen on that path is hosted by FlowPrime and branded as you: sign-in, sign-up, e-mail verification, password reset, two-factor, invitation acceptance, the team page. Your app receives a signed-in person with their company already resolved.

01 Your landing page a buy link. No form. 02 Stripe Checkout on your account 03 Welcome mail sets their password 04 First login their workspace, as admin INSIDE YOUR APP No login screen. No password reset. No invitation mail. No team page. Two lines of setup, one element in the header, and a map from seat to role.
A buyer can pay before any account exists. The purchase is held against the e-mail that paid, and the customer workspace is born at their first login. Nothing is created from a signup form alone, so a paid-only product has no junk accounts to clean.
What the login finds

What the login finds decides where they land.

Every sign-in on your product asks one question: what does this person hold here? The answer is checked in one order and the first hit wins: a seat in a company, a purchase not yet redeemed, your product’s open door for consumers, or nothing. Nothing is refused with the way in spelled out, in your words.

1 A seat Invited by an owner, or the owner themselves. Their company’s workspace, at their role 2 A purchase They paid, and have not signed in yet. A brand-new customer workspace, as its admin 3 Nothing, on a consumer product Your product serves people, not companies. In, as your clientele 4 Nothing No seat, no purchase, no open door. Refused, with the way in spelled out
Teams

The team page is the access list.

Who can act inside a customer’s workspace is exactly who its owner seated, at the role the owner chose. Invitations are by consent: nobody is added to a company silently, not even by you. Removing a seat ends every session that person had. Your app decides what each seat may do; FlowPrime decides who holds one.

Acme Imports / Team 4 of 5 seats WHO SEAT ROLE IN YOUR APP Helena owner admin Ana member supervisor Carlos member operator [email protected] invited waiting to accept Invite by e-mail Invite support FLOWPRIME DECIDES who is in, and at which seat YOUR APP DECIDES what each seat may do Hosted, branded as you. The first person on a customer workspace is its admin; everyone after starts at your default role, promoted inside your app.
In code

A seat, or your clientele. The difference is one line.

Both arrive as a signed-in person naming exactly one account. For a seat that account is their company and the data is shared with everyone seated in it. For your clientele that account is yours, and each person sees only what they made. Your app tells them apart once, at the top of the request.

One branch
const c = sdk.claims(request)validated and projected alreadyif (c.account_role === "consumer") return serveClientele(c)return serveSeated(c)owner | member
A seat they act for their company What arrives
{  sub:          "u_7f3a...",the person  account:      "acc_9k2m...",THEIR company  account_role: "member"owner | member}
What your app does
// their seat decides what they may dorequire(ws.member(c.sub).role === "admin")from the rowconst db = open("orgs/ws-" + c.account)their storereturn db.processos.all()no filter: it is shared
Clientele they act for themselves What arrives
{  sub:          "u_c81d...",the person  account:      "acc_operator...",YOUR company  account_role: "consumer"the difference}
What your app does
// no registry row, no seat, no roleconst db = open("orgs/ws-" + c.account)your one storereturn db.requests  .where({ ownerSub: c.sub })THE partition

FlowPrime guarantees which account the token names: it is unforgeable, it can never name two, and it dies when the seat does. The line that partitions your clientele is yours. Delete it and every one of them sees the others, and nothing outside your code will notice.

One login, many places

The same person, in every company that seated them.

A consultant seated by three clients, a retoucher who works for three studios, a broker invited into a client’s own account: one e-mail, one password, and a switcher in your header that re-issues the token for the company they pick. Work they do in a client’s workspace carries their real name, meters against the client’s plan, and vanishes from their reach the day the client removes the seat.

The retoucher one login the switcher picks one Her own studio owner seat, her plan A second studio member seat, their plan A third studio member seat, their plan one company per token The choice is remembered per session and survives refreshes. The token names one customer workspace and can never name two, and the reference pattern gives each its own store, so a leak between them is not something you can write.
The same for every shape

What happens after the first login.

You do not design this part either. Verification, invitations, removals and returns run the same way for a paid product, a free one and an internal tool, and the same whether the owner removes somebody from the team page or the person leaves on their own.

Born paid, invited or signed up Active re-checked every few minutes, silently Removed every session ends; a stale cookie dies at the next check Returned a new invitation, at today’s role History their name stays on what they made TIME Not everybody walks the whole line. Most seats are born once and stay active for the life of the company.
SUPPORT

Only through the owner’s invitation

When a customer wants hands-on help, their admin invites your support address from the team page. Support arrives as a visible seat under its own name, every change is attributed to it, and the owner revokes it when the engagement ends. There is no back door, not even for us.

PROOF

An e-mail binds nothing until it is proven

A signup on a fresh address holds a login for 72 hours and then evaporates unless the mailbox is verified. A purchase, an invitation or a verified signup for the same address always wins over an unproven one, so nobody can squat a customer’s e-mail and wait.

LEAVING

Remove a seat and the access is gone

Removal ends every session that person has in your product, and your app refuses any token that outlives it. Their name stays on the records they created; a company’s history is never rewritten to settle a departure.

The negative space

Eight things that cannot happen.

Every one of these is a test that attempts the attack and asserts the refusal, in the identity service and in the reference app it ships with. They are the reason the page above can be short.

01

A token with two hats

A staff role and a customer seat never share a token. The format cannot express the mix, and a tampered one fails its signature.

02

A wrong-door token

A console token presented to your app, or a customer token presented to a console, is refused. Which door somebody came through is part of who they are.

03

Access after removal

Removal ends every session. A refresh cannot re-issue the seat, and the app refuses any cookie that outlives it.

04

A squatted e-mail

Unverified signups expire. A verified purchase, invitation or signup for the same address evicts or claims the unproven one.

05

A borrowed identity

Nobody acts under another person’s name: not support, not an administrator, not a machine. Every write carries the real user who made it.

06

A reused refresh token

Refresh tokens are single use. A replay revokes the whole family, and a session that switched company keeps the company it switched to.

07

A leaked key worth more than one seat

A machine credential is pinned to one seat in one company. Stolen, it is worth exactly that seat, and the owner removing the seat kills it.

08

A platform key in your deployment

Nothing your deployment holds can reach another organization or a platform surface. Every credential you hold is scoped to you and revocable on its own.

Side by side

The whole map on one page.

Read the last column first. It is the one that actually decides which row you are.

Shape Who may create a login What a login gets Best when
Checkout-first, with teams Closed: they pay, or you invite Their own workspace, bought Companies buy your product and bring a team. No public form means no junk logins.
Sign up, then buy Open: a public sign-up form Their own workspace, bought Your buy flow lives inside the product, or people need a login before they would ever buy.
Free tier Open: a public sign-up form Their own workspace, free Product-led growth: try it, then upgrade in place with no second customer workspace.
Consumer app Open: a public sign-up form Their own records inside yours You serve people, not companies: a marketplace, a community, an audience.
Paid consumer app Closed: they pay for access Their own records inside yours You serve people, and access is the thing you sell. No customer workspace is ever created.
Internal tool, or a closed group Closed: you invite them A seat in the workspace you run The product serves your operation, or a group you run by hand. Same team page, same roles, same revocation.

Six rows, because those are the six cells the two flags actually span. Moving between them is a flag on the client your product registers at boot, not a change to your code. The two combinations missing from this table are the two the builder draws as empty.

The reference

Every dial, in detail.

The blocks the question marks in the builder point to. One per option, and every one jumps back to the builder.

Who may create a customer login

Anyone can sign up

a public form on your sign-in screen

Your sign-in screen carries a create-account link. Anyone may make a login and prove their e-mail, which costs them nothing and, on its own, gets them nothing: a bare login holds no customer workspace and no seat. What it is worth is the other question on this builder.

Open does not mean unguarded. Unverified sign-ups expire after 72 hours, the form is rate limited, and an e-mail that already belongs to somebody becomes a login challenge rather than a second identity.

AllowSelfRegistration = trueon your product's client// a "create account" link appears on sign-in
Back to the builder

Only people you let in

no public form: they pay, or you invite

No create-account link exists. A login is then born in exactly two ways: your checkout provisions the buyer and mails them a link that sets their password, or you, or one of your customers, invite them by e-mail. Both prove the e-mail before the login exists, so there is no junk to clean up.

Both paths are always live together. Closed is not a choice between selling and inviting: a checkout-first product still invites teammates every day.

AllowSelfRegistration = falsethe default// no link; checkout and invitations still work
Back to the builder

What a customer login gets

Their team shares a workspace they buy

born at their first sign-in

Pick this when more than one person will need to see the same records. The purchase writes a grant against the e-mail that paid, and the first sign-in redeems it: a company is created, the buyer takes the owner seat, and your app sees a brand new customer workspace to fill. Their colleagues join that same workspace by invitation, at roles your app assigns.

Only products you declare as selling a customer workspace do this. Upgrades and renewals move the plan and never mint a second company.

// on payment, the pipeline writes the grantPOST /orgs/{you}/accounts/grants { email }account_role: "owner"at their first sign-in
Back to the builder

Their team shares a free workspace

born when they verify their e-mail

Verifying the e-mail earns the customer workspace, with no card. What that workspace may do is a licensing policy: a permanent free floor, a time-boxed trial whose clock starts at first use, or both. Upgrading later is a plan change on the same customer workspace, so nothing moves and nothing is recreated.

One trial per e-mail per product, ever. An expired trial is remembered, so signing up again on the same address does not restart the clock. This needs a public sign-up form to hang on.

SignupGrantsAccount = trueneeds the form above// verification writes the very same grantaccount_role: "owner"at their first sign-in
Back to the builder

They join the workspace you run

nothing new is created

No new company is created. The people you invite take a seat in your own workspace, or in one you run on somebody else’s behalf, and your app gives each seat a role. This is the shape of an internal tool, and of a closed group you run on somebody else’s behalf.

A seat comes only from an invitation or from a purchase. Somebody who signs up holding neither is refused at the door, which is why a public form cannot fill your workspace by itself. Your own staff are seated here like anybody else: inside the product they wear the customer hat, and their administrative role stays out of the token.

{ account: YOURS, account_role: "member" }db.projects.all()shared with everyone seated
Back to the builder

They see only what they made

no company, no seat, no team page

Pick this when nobody ever needs to see anybody else’s records. Your product serves individuals, and everyone who arrives is an end customer of your one workspace: a login and their own records, never a company and never a seat, and they never appear on a team page. Their use meters against your plan, because they are your customers rather than your tenants.

The day one of them needs a real seat, an invitation or a purchase gives them one, and it outranks their clientele standing from that sign-in on.

{ account: YOURS, account_role: "consumer" }db.records.where({ ownerSub: c.sub })the partition
Back to the builder

Teams inside a customer

Their admin invites their colleagues

a seat at acceptance, never at send

The owner of a company invites colleagues by e-mail from a hosted team page. A person is seated only when they accept; existing users are never added silently. That page is the access list your app enforces: everyone on it may enter, nobody else can.

Removing a seat ends every session that person had in your product, immediately, and the app refuses any cookie that outlives it.

POST /accounts/mine/invites { email }nothing exists yet// when they accept, and only then:AccountMember row createdthe seat
Back to the builder

Different people, different access

from your own records, not the token

FlowPrime says who is in; your app says what they may do. The first person to arrive on a customer workspace is its admin; every later seat starts at your default role and is promoted by the admin inside your product. Roles live in your own registry, never in the token.

A role is never derived from a claim after the first sight. That rule is what keeps a switch, a refresh or a transfer from silently changing somebody’s powers.

const m = ws.members.find(c.sub)require(m.role === "admin")your own row// never require(c.account_role === "owner")
Back to the builder

Their plan limits how many can join

checked at activation, not at invite

A plan may limit how many seats a company may activate. The invitation still goes out and the person is still seated; your app holds them pending with an upgrade prompt until a seat frees up or the plan grows. No lost invitation, no error page.

Membership and quota are two systems on purpose: an invitation is a fact about the team, a seat limit is a fact about the plan.

if (ws.activeSeats >= plan.seats)  seat.status = "pending"not an error page
Back to the builder

One person works for several customers

the switcher re-issues the token

A person may hold seats in any number of companies and own one of their own. A switcher element in your header lists them; picking one re-issues the token for that company, and your app simply resolves a different customer workspace. The choice is remembered per session and survives refreshes.

Work done in a client’s company carries the person’s real name, meters against the client’s plan, and ends when the client removes the seat.

POST /v1/auth/switch-account { account }open("orgs/ws-" + c.account)a different store
Back to the builder

Who else may come in

Your support team can be let in

a consent seat; no back door exists

When a customer wants hands-on help, their admin invites your support address from the team page; a one-click affordance pre-fills it. Support arrives as an ordinary, visible seat under its own name. Everything it changes is attributed to it, and the owner revokes the seat the moment the engagement ends.

There is no break-glass path. Not for you, and not for the platform: an administrator without a seat is refused by your app like anyone else.

// the OWNER sends it, from their team pagePOST /accounts/mine/invites { support@you }// no endpoint lets you seat yourself
Back to the builder

Another system connects, like an ERP

client credentials pinned to one seat

An ERP, a scheduler or a nightly export authenticates as a dedicated service user that holds a real seat in the company it serves. It appears on the team page, every write it makes is attributed to it, and the owner removes it like any member. Its credential is pinned to that one seat.

A leaked machine credential is worth exactly one seat in one company, never more, and removing the seat kills it.

client_credentials -> token{ account: pinned, account_role: "member" }// owner removes the seat, the key is dead
Back to the builder

An AI assistant, acting as the person

registers itself, signs in as the person

An assistant a customer connects to your product through MCP acts as that customer: same seat, same role, same attribution. It registers itself as a client, is locked to interactive sign-in, and can never obtain a machine or a platform token.

Nothing an assistant does is anonymous. The team page shows the person; the audit trail shows the person.

// it registers itself, the human signs increatedBy: c.subthe person, not the assistant
Back to the builder

How they prove who they are

Two-factor sign-in

TOTP, challenge, recovery codes

Time-based one-time codes with a hosted enrollment screen, a challenge at sign-in, and recovery codes. Your app never sees the second factor; it receives a signed-in person or nothing.

Sign-in, verification and code endpoints are rate-limited and lock out on abuse.

// after the password, before any tokenPOST /mfa/challenge { code }
Back to the builder

Sign in with Google and the like

per-organization providers

Sign in with a social provider, configured per organization on the hosted sign-in screen. The identity that results is the same platform identity a password would produce: one person, one e-mail, one set of seats.

A social sign-in never creates a second identity for an e-mail that already exists; it binds to the existing one after proof.

// configured per organizationGET /auth/login -> "Continue with Google"
Back to the builder

Your brand on every screen

per organization, every hosted screen

Every hosted screen, from sign-in to the team page and every refusal, is rendered under your logo, your colors and your language, on your own subdomain. Refusals speak in your product’s words and link the way in you chose.

Portuguese and English ship today; the wording of every guidance message is per organization.

branding: { logo, colors, locale }set once// every hosted screen, for every customer
Back to the builder
In the wild

Six products, six answers.

One for each row of the table above, in the same order. Different trades, different shapes, and not one of them built a sign-in screen.

  1. 01

    A customs-compliance product

    Checkout-first, with teams

    Importers subscribe, and each importer’s team works its own files. A customs broker seated by four clients switches between their workspaces from the header; what she files in each carries her name and counts against that client’s plan.

    The client controls who works its files. The broker keeps one login.

  2. 02

    A studio management product

    Sign up, then buy

    A retoucher creates a login to accept the studio that invited her, and works there for a season. Two years later she opens her own studio: a purchase turns the same login into an owner. Both studios now sit in her switcher.

    The login came first; the business came later. Nothing had to be merged.

  3. 03

    A note-taking product

    Free tier

    Sign up, verify, and a workspace opens with a small permanent allowance. A 14-day trial of the full plan starts the first time they open it, not the day they registered. Upgrading is a plan change; the notes never move.

    Product-led growth, with one customer workspace per person, ever.

  4. 04

    A neighborhood services app

    Consumer app

    Residents sign up and see their own requests, and only theirs. There is no team page because they are not a team: they are the operator’s clientele inside the operator’s one workspace. The operator’s own staff hold the seats.

    People, not companies. One workspace, thousands of customers.

  5. 05

    A certification exam trainer

    Paid consumer app

    Candidates buy a year of access on the landing page and set a password from the welcome mail. Each one signs in to their own practice history and their own results, and no company exists anywhere: no team page, no seats, and no colleague who could ever see their score.

    Money before the login, and every candidate alone with their own record.

  6. 06

    A precision-parts manufacturer

    Internal tool, or a closed group

    Forty technicians on two shifts share one maintenance-scheduling product. The plant is the only company, the foreman is its admin, and a technician who leaves loses access the minute the seat is removed.

    The same team page, roles and revocation, with nobody buying anything.

Designed, not built

And six things we have deliberately left for later.

The model already has a place for each of these. Each one waits for the first product that actually needs it, and none of them requires changing anything above.

Parent companies

A group with several subsidiaries under one contract will nest companies under a parent. Roll-up visibility and billing stay in your app. The flat model forbids nothing here.

Ownership transfer

A company sold to a member of its team keeps its id, its workspace and its history; the owner seat, the plan and the bill move to the buyer. Designed end to end; ships with the first real transfer.

Account-scoped API keys

A key issued by a company owner that acts as an integration seat, without a dedicated service user. The interim form, a service user with a pinned seat, is the same shape and converges on it.

Per-customer enterprise SSO

A customer federating its own identity provider plugs in at sign-in. Seats and roles are untouched, so it lands without a redesign.

Invite-gated consumer signup

An invitation that admits somebody as your clientele without seating them in a company: the shape a closed beta, or a friends-invite-friends product, actually needs. Invitations today always grant a seat, so this waits for the first product that needs it. Until then the gate lives in your own product, in front of the hosted sign-up screen.

Per-customer audiences

A product whose customers each have their own end-customers, like a studio’s clients viewing their gallery, needs a consumer door per customer workspace instead of one per product. The token already has the shape.

Pick one and start

The door is a flag. Change it the week you learn something.

Every shape here is configuration on the client your product registers at boot, not architecture. Start with the simplest door that could work, and open another when the numbers tell you to.