Account

Signing in

The three ways into the Envless dashboard, how one-time code sign-in, the optional second factor and step-up verification work, and why account access still is not access to your variables.

An Envless account is an email address. There is no username, no password, and no separate sign-up form: the first time an address completes a sign-in, the account and a workspace are created for it. Everything starts at envless.cloud/dashboard/auth.

The ways in

RouteWhat you doWhere it lands
Emailed codeType your email, then type the 6-character code we send back/internal/users/auth-mail, then /internal/users/auth-otp
GoogleContinue with Google, approve in the provider popup/internal/users/auth
GitHubContinue with GitHub, approve in the provider popup/internal/users/auth

A magic link exists underneath the emailed code, but Envless never sends you one. That is covered below, because the difference matters if you were expecting a clickable link in your inbox.

The security model

Envless authenticates with one-time codes rather than a stored password, re-verifies before the actions that destroy or reveal a credential, and can ask for an authenticator app on top if you turn one on. Three mechanisms, two of them built on control of your inbox:

MechanismWhen it runsWhat it protects
One-time code sign-inEvery sign-in, unless you use Google or GitHubAccount access, with no reusable credential anywhere
Two-factor authenticationEvery sign-in, once you have turned it on. Off by default, per userAccount access against a compromised inbox or provider account
Step-up verificationBefore the destructive and credential-revealing actions listed on that pageThose actions against a hijacked browser session

Sign-in is passwordless and, by default, single factor: control of the email address. Step-up verifies that same factor again, which is exactly the distinction that decides what it defends against, a stolen session rather than a compromised inbox. The one way to add a genuinely second factor is two-factor authentication, an authenticator app you enable yourself. There is still no SMS code, WebAuthn, passkey or hardware key anywhere in the dashboard or the API.

What passwordless buys you

  • There is no reusable credential to leak. No password is set, so nothing can be reused across sites, dumped in someone else's breach, sprayed against Envless, or phished and replayed later. Every emailed code is single-use and dies in 10 minutes.
  • There is nothing on your side to store or rotate. The one secret worth protecting in Envless is the workspace passphrase, and that is a different thing entirely: it never reaches the server, and it is what actually decrypts variables. See Choosing a passphrase.
  • There is no password hash to steal and crack offline, because one was never created. Be precise about what that does not cover: while a code is live, the code and its sign-in link are stored in the clear next to the address they were issued for, so a database read inside that 10 minute window is a sign-in rather than a cracking exercise.

What it does not buy you

  • Without two-factor, your Envless account is exactly as strong as your email account. Anyone who can read your inbox for 10 minutes can request a code and sign in as you. If you sign in with Google or GitHub, it is exactly as strong as that provider account.
  • One factor means one mistake. With nothing but the emailed code, there is no second gate behind a forwarded code, an inbox rule, a mail client left open on a shared machine, or a mailbox still delivering to someone who has left. Turning on two-factor authentication puts an authenticator app in that position, and a recovery code is then the only other way through.

Two practical consequences. First, turn on two-factor authentication if the account can reach anything that matters. Second, harden the inbox anyway, because it stays the first factor and it is the whole account for anyone who has not enrolled: enable MFA on your email provider and on the Google or GitHub account you link, and do not use a shared team alias that several people can read as the address on an Envless account.

Sign in with an emailed code

Enter your email

Enter is enough, or use the submit button. An invalid address is rejected in the browser before a request is made, and again by the API with 400.

Envless emails a code

Six characters drawn from a 32-symbol alphabet, ABCDEFGHJKLMNPQRSTUVWXYZ23456789, with the ambiguous I, O, 0 and 1 removed. The email prints it split in half, as ABC-DEF. Requesting a code also expires every older code for that address, so only the newest one works.

Enter the code

The form at envless.cloud/dashboard/otp takes six slots. It uppercases what you type, and a paste is stripped of everything that is not a letter or a digit first, so pasting abc-def works. The page is only reachable after you have asked for a code; landing on it cold sends you back to the sign-in form.

You are signed in

A correct code clears the code and its link from the record, so neither can be replayed, and the browser completes the sign-in and lands on the dashboard. With two-factor authentication on, it lands on the app-code screen instead.

The numbers

PropertyValue
Code length6 characters, letters and digits, not digits only
Alphabet32 symbols, ambiguous I, O, 0, 1 excluded
Expiry10 minutes from the moment it is issued
Attempts5. A sixth attempt is refused even if the code is right
Live codes per address1. Issuing a new one expires every older code for that address

The Resend link on the code form issues a fresh code. Envless does not throttle how often you can ask, by email address or by network address, so a code that never arrived can be requested again straight away. Each new code expires the one before it, so work from the most recent email and ignore anything older.

Since nothing limits how many codes you can ask for, what protects the account is the code itself: 6 characters from a 32-symbol alphabet, one live code per address at a time, 10 minutes of life, and 5 attempts before that code is dead whatever you type next. Asking for another code does not widen the window, it replaces it.

A wrong code, an expired code, a code that has already burned its 5 attempts, and an address with no live code all return the same 401 and the same sentence: "The code you entered is invalid or has expired." The response never reveals whether an account exists for the address you typed.

Expiry is enforced when the code is read, not by the cleanup job, so a late sweep is a disk-space matter and never a valid-code-that-lingers matter. Expired records are cleared by a job that runs every 10 minutes.

Every code request also mints a Firebase email sign-in link and stores it beside the code. That link is never emailed to you. The sign-in email carries the code and the sentence that it expires in 10 minutes, and nothing you can click to sign in. Verifying the code is what hands the link to your browser, which then consumes it to complete the sign-in. So the magic link is real, but it is the mechanism behind the code rather than a second way to receive a sign-in.

The dashboard will honour such a link if one reaches it: arriving at the app with apiKey, email, lang, mode and oobCode in the query string signs you in with it, after signing out whoever is currently signed in on that browser. Since Envless does not send those links, this path only matters for a link produced elsewhere in the same Firebase project.

A sign-in link is a bearer credential for the account. Anything that can read one, including a browser history entry, a chat preview, or a URL logged by a proxy, can sign in with it. This is another way of saying the same thing as above: with one factor, whatever touches the sign-in material has the account. With two-factor authentication on, such a link completes the first factor and stops at the app-code screen.

Sign in with Google or GitHub

Continue with Google and Continue with GitHub open a provider popup rather than redirecting the tab. Closing that popup, or having it blocked by the browser, is treated as a cancellation: no error is shown, and the buttons simply become clickable again.

The GitHub button asks for the user:email scope. If GitHub returns no address on the credential itself, which is what happens when your address is private, Envless calls the GitHub API with the access token it just received to resolve it. If no address can be resolved either way, the sign-in fails, because an Envless account is keyed by email and cannot be created without one.

Both providers finish at /internal/users/auth, which is also where the emailed code flow ends up once the browser has consumed the sign-in link. That endpoint resolves the account from the Firebase user id on the verified token, not from the email in the request body, so what puts several sign-in routes on one Envless account is their provider identities being linked to one Firebase user. Linking is what Connect does in Account settings.

First sign-in creates the account

There is no sign-up step to complete first. An address that is not yet known gets a user record and a workspace named after you (Jane's Workspace) in the same request, and if any part of that fails the half-created account is rolled back rather than left behind.

Deletion is final. Signing in with an address whose account was deleted returns "This account has been deleted and cannot be recreated." rather than creating a fresh one.

Connected accounts, and the email you cannot change

Account settings lists Google and GitHub with a Connect or Disconnect button each, so you can add a provider to an account that started with an emailed code, or drop one you no longer want.

While either Google or GitHub is connected, the account email cannot be changed. The field is locked in the dashboard, and the API refuses the request outright with 409 and "Disconnect Google and GitHub before changing your email!". To move an account to a new address, disconnect both providers first, change the email, confirm the link sent to the new address, then reconnect.

A pending change shows under the field as "Pending. Confirm the link we sent to ...", and the change only takes effect once that link is confirmed.

Signing in is not decryption

This is the part that makes single-factor sign-in survivable. Being signed in reveals no variable value. Values are encrypted in your browser with a key derived from the workspace passphrase, which Envless never receives, so a browser that has only signed in is a locked workspace: names, types, secret flags and the whole product and environment hierarchy load normally, every value stays ciphertext, and version history shows a banner instead of anything readable. Even exporting the raw ENVLESS_KEY from Settings → Encryption asks for the passphrase again, so a session alone cannot produce it. See Unlocking the dashboard.

That is not the same as account access being harmless. Whoever holds the session reads the entire plaintext hierarchy with no further check, and edits variables one at a time. The louder actions, inviting or removing members, changing roles, deleting environments and projects, creating an API key, revealing a webhook signing secret, ask for a step-up code first, which without two-factor goes to the same inbox that just let them in. And on a device where the workspace has already been unlocked, the derived key is cached locally and values decrypt exactly as they do for you. What account access alone does not hand over is plaintext on a new device.