Two-factor sign-in, and workspaces that require it
Rezee accounts can now ask for a code from an authenticator app after the password, with ten recovery codes. An owner or admin can require it of every member, and a member without one is shown how to fix it instead of a wall of errors.
Oct 13, 2026 · 11 min read · Kash Gohil · LinkedIn · X
A password is one secret, and it leaks in ordinary ways. Somebody reuses it on a site that gets breached. Somebody types it into a page that only looks like ours. Until September, a Rezee account with a password had nothing behind that password.
Two changes landed in mid-September. The first is two-factor sign-in for any account with a password. After the password, Rezee asks for a six-digit code from an authenticator app. The second is a workspace setting. With it, an owner or admin can require a second factor of every member. Rezee then refuses that workspace to a member who has not turned one on.
This post covers what a member sees, what an admin sets, how recovery works, and how the phone and the CLI fit in. It also covers a few choices we made that you might not expect.
Turning it on
Two-factor sign-in is under Settings → Security, in a card called "Two-factor sign-in". Its description is the short version of this post: "Ask for a code from an authenticator app after your password. Tokens and SSH keys are not affected."
To turn it on:
- Click Turn on and enter your current password.
- Scan the QR code with an authenticator app. If you cannot scan it, the page shows the key so that you can type it.
- Enter the six-digit code that the app shows, and click Turn on.
- Save your recovery codes.
Nothing changes until step 3 succeeds. If you stop after step 2, the account still signs in with the password only. If you start again, Rezee makes a new key and the old one is useless.
The codes are standard time-based one-time codes, as RFC 6238 describes them: HMAC-SHA1, six digits, and a new code every 30 seconds. Any authenticator app that follows that standard works. Rezee accepts the code for the current 30 seconds, and also the one just before and the one just after. That covers a phone whose clock is a little wrong.
Ten recovery codes, shown once
When the first code is correct, the page shows ten recovery codes. Each looks like k7qm2-x4r9p. The panel says:
Save these recovery codes somewhere safe. Each works once, and they won't be shown again.
There is a Copy codes button, and an I've saved them button to close the panel. Rezee stores only a hash of each code, so we cannot show them to you again. That is the point of a recovery code. If our database could give it back, so could a copy of our database.
After that, the card reads "On · 10 recovery codes left". The count goes down each time you use one.
Signing in
With two-factor sign-in on, a correct password no longer starts a session. It starts a challenge. The sign-in page asks for the next step:
Enter your code
Open your authenticator app for the six-digit code.
Under the field it says "Lost your phone? Enter one of your recovery codes instead." A Start over link takes you back to the password.
These are the rules of a challenge:
- It lasts five minutes and allows five wrong codes. After that it is dead, and the answer is "this sign-in has expired; enter your password again".
- The code step has its own rate limit. Six digits are only a million possible codes, and the password step already used the password's limit. Each address gets ten tries, and one more every 30 seconds.
- A code works once. Rezee remembers the last 30-second step that you used. It refuses that step and every earlier one. A code that somebody saw over your shoulder is useless after you sign in with it.
- A recovery code works in the same field. You can type it with or without the dash, in capitals or not. Each code works once.
When you sign in with a recovery code, a message tells you how many are left, for example "Recovery code used. 9 left." When you use the last one, it says "That was your last recovery code. Make new ones in Settings → Security."
What a second factor protects after sign-in
A second factor that only guards the sign-in page is easy to get around. A person who steals a session cookie can change the password, turn off the second factor, and keep the account. So a code is required in three more places:
- Changing your password. With two-factor sign-in on, the form also asks for a code. A stolen session alone cannot take the account by changing its password.
- Turning it off. This needs your current password and a code.
- Making new recovery codes. This also needs your password and a code. Every earlier recovery code stops working.
A recovery code is accepted wherever a code is asked for. If you lose your phone, you can sign in with a recovery code, turn two-factor sign-in off, and turn it on again with the new phone.
None of this works with a token. Turning it on, turning it off and making new codes need a signed-in browser. A token gets "change two-factor sign-in from a signed-in browser". A token is a credential that somebody made. If a leaked token could change the second factor, it could lock the owner out, or remove the protection that should sit beside it.
A password reset by email leaves the second factor in place. The reset signs the account out everywhere and revokes its personal access tokens, but it does not touch the authenticator. A person who gets into your email can choose a new password, and still cannot sign in without your phone.
On our side, Rezee stores the authenticator key encrypted, and the recovery codes as hashes. It also writes an account audit log. The log records these events:
- turning it on and turning it off
- making new recovery codes
- each use of a recovery code, with the number left
- each failed code
The database refuses changes to that log.
The phone and the CLI
Neither the phone app nor the CLI asks for a code. Both sign in through the website, so the code step happens there.
The phone opens the system browser to Rezee's normal sign-in page, and signs in with OAuth and PKCE. You enter your password and your code on that page, and the app gets its token. We did not build a second sign-in form for the phone. A second form is one more place for the code step to be missing.
The CLI uses device login. rezee auth login prints a short code and opens a browser tab. You approve the machine in a tab that is already signed in, and that session already passed the code step. The CLI then gets a personal access token.
After that, tokens and SSH keys never ask for a code. They are credentials that a person made on purpose and can revoke one at a time. A code on every git push would only teach people to make tokens that never expire.
One result of this is worth knowing. Turning on two-factor sign-in does not revoke tokens that you made before. If you turn it on because you think your password leaked, also revoke your old tokens, or reset your password, which revokes them all.
Requiring it for a workspace
A workspace's sign-in policy is under Settings → Authentication. Only owners and admins can change it. Anybody else sees "Only owners and admins can change how people sign in".
The page has one switch, Require a second factor. Under the switch, before you touch it, is the number of people that it affects:
3 people have no second factor and would be shut out.
When everybody is covered, it says "Everybody here already has one." We put the number beside the switch on purpose. Requiring a second factor shuts out everybody who has not turned one on. The admin should know how many people that is before the change, not after.
The count includes active human members who have no second factor and no account from the workspace's identity provider. It leaves out agents and deactivated members.
Two rules apply to the switch:
- You must be covered first. If your own account has no second factor, turning the policy on fails with "turn on two-factor sign-in for your own account first, under Settings → Security". Without that rule, an admin's next request would be refused, including the request that turns the policy off again.
- Each change goes to the workspace audit log as
workspace.mfa, with who changed it and the new value.
When the policy is on, the same line reads "3 people have no second factor and cannot open this workspace." The number goes down as people turn on their second factor.
What a member without one sees
Say kash is the owner and turns the policy on. aki already has a second factor. power does not.
On the web, power does not see an empty workspace made of error messages. The workspace shows one screen:
rezee requires two-factor sign-in
Turn on an authenticator app for your account and this workspace opens again. Your other workspaces are unaffected.
The screen links to power's own security settings. Those settings are outside the gate, so the link works. When power confirms the first code, the server updates power's own list of workspaces. The workspace opens without a reload.
The phone shows the same message, with a Set it up on the web button. The phone has no screen for account security, so it sends power to the web page that has one.
Over the API and the CLI, every request in that workspace answers 403:
this workspace requires two-factor sign-in - turn it on under Settings → Security
Where the gate sits, and why
The requirement is checked at the workspace, not at sign-in. A session belongs to a person, and the policy belongs to one workspace. If the gate were at sign-in, a member of two workspaces would lose both because of one. Worse, they would also lose the settings page that fixes the problem. With the gate at the workspace, power keeps their other workspaces and their account settings.
The gate checks every credential that a person holds, not only the browser session. That includes personal access tokens, the CLI's token and the phone's token. A token is made from a session. If a token could pass where the session cannot, the token would be the way around the policy. A test checks that a person's token is refused like their session. git follows the same rule. A clone or a push with a token or an SSH key is refused too, except a clone of a public repository, which anybody may make.
The settings card says "Tokens and SSH keys are not affected". That means a token never asks for a code. It does not mean a token gets past the policy. In a workspace that requires a second factor, Rezee refuses the token of a member without one, the same as their session.
Two kinds of account are exempt:
- Agents. An agent has no phone, and nobody can carry one for it. Agents have their own controls: scoped tokens and the approval gate.
- Accounts from the workspace's identity provider. A person whose account here comes from your SSO signs in at the provider. The provider decides what signing in costs, including its own second factor. If Rezee also asked them for a code, it would lock out exactly the accounts that the admin already controls centrally.
When the policy is off, the check costs nothing. The flag is on the workspace row, and every request has already read that row.
What it does not do
- Authenticator codes only. There are no passkeys, no hardware security keys and no codes by SMS.
- No admin reset. An admin cannot remove another person's second factor. If you lose your phone and every recovery code, nothing in the workspace settings brings the account back. Keep the codes.
- No second factor on accounts from an identity provider. Turning it on needs a password, and those accounts have none. Their provider is where the second factor belongs.
- No account history page yet. Rezee writes the account audit log, but the app does not show it to you yet.
The security page lists this beside the rest of what we do and do not have.
FAQ
Which authenticator apps work?
Any app that supports standard time-based codes (RFC 6238) with six digits, 30-second steps and SHA-1. That is the default for nearly every authenticator app. If your app cannot scan the QR code, type the key that the page shows.
I lost my phone. How do I get back in?
Sign in with your password and one of your recovery codes. Then go to Settings → Security. Turn two-factor sign-in off with your password and another recovery code. Then turn it on again with the new phone. You get ten new recovery codes.
Do agents need a second factor in a workspace that requires one?
No. Agents are exempt, because an agent has no phone to carry. They are limited in other ways: by the scopes on their token, and by the gate that stops them before an action they cannot undo.
Does the CLI ask for a code?
No. rezee auth login sends you to the browser to approve the machine, and the browser sign-in is where the code step happens. After that the CLI uses its token. In a workspace that requires a second factor, that token works only if your account has one.