Signing in

How people sign in to Nixt Server — passwords, SASL mechanisms per protocol, lockout, OAuth tokens for JMAP apps, and the sign-in pages.

This page is for administrators and for the people whose mail the server hosts. It explains what you sign in with, how each protocol asks for it, what happens after too many wrong passwords, and how apps such as Nixt Mail sign in without ever seeing your password.

What you sign in with

WhereUser nameSecret
IMAP, POP3, SMTP submission, ManageSieveYour email address, for example alex@example.comYour password
CalDAV and CardDAVYour email addressYour password, sent with HTTP Basic authentication over TLS
JMAP—An OAuth access token, which an app obtains by sending you to the server’s own sign-in page
The server’s sign-in pagesYour email addressYour password

Only a user account can sign in. Groups, aliases and resources cannot, and nor can an account whose status is disabled or deprovisioned.

Passwords

  • Passwords are stored as Argon2id hashes. Nothing on the server keeps them in a readable form.
  • A password must be at least 14 characters (an organisation can lower this to 12, or raise it) and at most 256, and must not contain the part of the address before the @ when that part is 3 characters or longer.
  • An administrator sets a password with the admin API; see Domains and accounts.
  • People created by a directory sync can instead sign in with their directory password, checked against the directory each time; see Signing in with the directory password.
  • A password is never accepted over an unencrypted connection. Every listener either starts with TLS or refuses to take a password until STARTTLS has been used.

SASL mechanisms by protocol

MechanismWhat it sendsOffered
PLAINThe passwordOnly over TLS
LOGINThe passwordOnly over TLS
SCRAM-SHA-256-PLUSThe same proof, bound to the TLS connection it is sent overOver TLS 1.3 ended at the server, and listed first
SCRAM-SHA-256A proof the password is known, never the password itselfAlways, subject to the protocol’s own rules below
OAUTHBEARERAn OAuth tokenOnly over TLS
XOAUTH2An OAuth tokenOnly over TLS

Channel binding

SCRAM-SHA-256-PLUS ties the sign-in to the TLS connection it travels over (RFC 9266). If somebody in between holds a TLS connection of their own to the server and relays the sign-in through it, the server sees a different connection and refuses the sign-in, so an app that supports it knows nobody is in the middle.

It is offered on every mail protocol, first among the mechanisms, wherever TLS 1.3 ends at the server. It isn’t offered before STARTTLS, on a TLS 1.2 connection, or when a load balancer in front of the server ends TLS, because there is then no connection of the server’s own to bind to. An app that uses plain SCRAM-SHA-256 where -PLUS was offered, while claiming the server couldn’t bind, is refused: that is what an attacker hiding -PLUS from it would cause.

SMTP submission (ports 587 and 465)

  • AUTH is advertised only once TLS is active: on port 465 from the start, on port 587 after STARTTLS.
  • AUTH before STARTTLS is refused with 530 5.7.0 Must issue a STARTTLS command first.
  • MAIL FROM before signing in is refused with 530 5.7.0 Authentication required.
  • A wrong password gets 535 5.7.8 Authentication credentials invalid. After three failed attempts on one connection the server replies 421 4.7.0 Too many failed authentication attempts and closes it.
  • A successful sign-in gets 235 2.7.0 Authentication succeeded.

IMAP (ports 143 and 993)

  • Before TLS, the capability list includes LOGINDISABLED and offers only AUTH=SCRAM-SHA-256.
  • LOGIN before TLS is refused with NO [PRIVACYREQUIRED] LOGIN needs TLS; use STARTTLS, and a password mechanism with NO [PRIVACYREQUIRED] That mechanism needs TLS.
  • A failed sign-in carries [AUTHENTICATIONFAILED], which tells a mail app to ask for the password again rather than retry the same one.
  • UNAUTHENTICATE signs out without closing the connection.

POP3 (ports 110 and 995)

  • USER and PASS are available only once TLS is active; CAPA lists USER only then.
  • Before TLS, AUTH offers only mechanisms that do not send the password.

ManageSieve (port 4190)

  • Every mechanism waits for STARTTLS. Authenticating before it is refused with NO (ENCRYPT-NEEDED) "Use STARTTLS before authenticating".
  • A wrong password gets NO "Authentication failed".

CalDAV and CardDAV

A calendar or contacts app sends your address and password with every request. After a successful check the server remembers it for 30 seconds, so a changed password can keep working on one node for up to that long. Only successes are remembered; every wrong password meets the full check and the lockout.

Lockout

Wrong passwords are counted per account and per network, across every protocol and the sign-in pages alike.

WhatThresholdLock
One account10 failures within 15 minutesLocked for 15 minutes. Each further lock lasts twice as long as the last, up to 24 hours. A network the account signed in from within the last 24 hours is not locked out: it gets its own 10 failures.
One network (a /24 for IPv4, a /64 for IPv6)100 failures within 15 minutes, spread across at least 10 accountsLocked for 1 hour.
  • A successful sign-in clears the account’s count of failures.
  • An account that signed in successfully from a network within the last 24 hours is not affected when that network is locked. A hundred people behind one office address therefore do not lock each other out, while a password-guessing run from that address only locks the accounts it is guessing at.
  • Someone who knows your address cannot keep you out of your mail by guessing from somewhere else: where you signed in within the last day still lets you in.
  • While a lock is in force, even the right password fails, with the same answer as a wrong one.
  • An address that does not exist takes the same time and gets the same answer as a wrong password, so failures cannot be used to discover which addresses exist. Guesses at addresses that do not exist count towards the network’s lock as guesses at accounts do.
  • When a password is checked against a directory, a wrong one counts towards lockout like any other. A directory that cannot be reached does not count: nobody is locked out by an outage.
  • Every attempt is counted in the vsx_authentications_total metric by protocol and outcome.
  • An organisation sees the networks its own people’s failed sign-ins locked, and the operator lifts a network lock early: see Networks locked.
  • Every lock is in the audit log, once, when it is taken: an account’s in its organisation’s log, and a network’s in that organisation’s log and the operator’s, since a network lock refuses everybody signing in from there. Search the log for role sign-in to see them. See Roles and the audit log.

Two-step sign-in

A second step asks, after the password, for a passkey or for a code from an authenticator app such as Google Authenticator, Microsoft Authenticator or 1Password. It is asked on the server’s own sign-in pages: the ones an app opens to sign you in, the device approval page, and the quarantine page.

Whether it is asked is the organisation’s choice:

SettingWhat it does
optionalAsks everybody who has added an authenticator.
required (the default)Asks everybody. Somebody who has not added an authenticator adds one the next time they sign in, before they can go on.
offAsks nobody.
vsx admin org second-factor required

The same setting is security.second_factor in the runtime settings.

Adding an authenticator

When a second step is required and you have none, the sign-in page shows Add a second step after your password:

  1. Open the link on your phone, or add the key shown in groups of four to your authenticator app by hand. The key is shown this once.
  2. Enter the six-digit code the app shows, to prove the app has it. If the code is not taken, you can ask for a new key and start again.
  3. Write down or save the ten recovery codes shown next. Each one signs you in once in place of a code, for the day your phone is lost. They are not shown again.

Apps that manage your account can add an authenticator the same way through POST /account/second-factor and POST /account/second-factor/confirm, with your address, password and the first code.

Signing in with a second step

After your password, the page offers Use your passkey first when you have one for this server, and otherwise asks for the six-digit code from your authenticator app, or one of your recovery codes. A code works once, within a minute or so of being shown. Five wrong answers send you back to the password.

Passkeys

A passkey signs you in with your fingerprint, your face or your device’s PIN in place of the six-digit code. It cannot be phished: your browser offers it only on this server’s own pages, so a look-alike page gets nothing it can use.

To add one, open https://<your mail server>/account/second-factor (Your account › Sign-in and security), enter your address and password, and your current code if you already have a second step, then choose Add a passkey and follow your browser. The page says which server name the passkey will work on: the server’s own name, or a name at one of its domains. If the passkey is your first second step, the page then shows ten recovery codes, each of which signs you in once in place of the passkey. They are not shown again.

A passkey is a second step like an authenticator app, so wherever it is asked, your own password no longer opens IMAP, SMTP submission, POP3, ManageSieve or DAV: see Mail apps and a second step.

Each organisation decides with three runtime settings, or from the command line:

SettingValuesWhat it decides
security.passkeysallowed (the default), offWhether people may add passkeys and use them. With off, passkeys already added wait unused and do not count as a second step.
security.passwordlessoff (the default), allowedWhether somebody may sign in with a passkey alone, with no password.
security.user_verificationrequired (the default), preferredWhether the device must check it is the person — fingerprint, face or PIN — every time. required refuses a security key without a PIN; preferred also takes one.
vsx admin org passkeys allowed
vsx admin org passwordless allowed
vsx admin org user-verification required

Administrators sign in with a passkey

An organisation’s administrators can change everything about it, so by default they take their second step with a passkey, and only a passkey: a code from an authenticator app can be typed into a phishing page and used at once, and a passkey cannot, because it belongs to this server’s name. An administrator who has no passkey yet is shown where to add one, under Sign-in and security (/account/second-factor) with their password and code, and is issued nothing until they have.

SettingValues
security.admin_second_factorpasskey (the default), any. any lets administrators take their second step any way anybody may.

Where the organisation has switched passkeys off, this cannot be asked, and administrators sign in as everybody does.

Signing in with a passkey alone

Where an organisation allows it, the sign-in pages also offer Sign in with a passkey, and your browser may offer the passkey as you start typing your address. The device must then check it is you, so the passkey alone is still two factors: something you have and your fingerprint, face or PIN. The sign-in carries on exactly as one with a password would.

A passkey whose signature counter goes backwards is what a copied authenticator produces. That sign-in is refused, written in the audit log under the account it tried, and counted by the passkey-went-back alert, which every organisation that has not chosen its own alerts has, sent to its administrators. Failed passkey answers count towards lockout as wrong codes do.

Mail apps and a second step

IMAP, SMTP submission, POP3, ManageSieve, CalDAV and CardDAV cannot ask for a code. Wherever a second step is asked of you, your own password no longer signs in to those; use an app password for each mail app instead. Apps that sign in through the server’s own page, such as Nixt Mail, ask for the code there.

A lost phone

An administrator removes your authenticators and passkeys, which also signs you out everywhere:

vsx admin people second-factor ada@example.com
vsx admin people remove-second-factor ada@example.com

Then add a new one the next time you sign in. A helpdesk or a domain administrator can do this for people whose role they could give themselves; the second step of an organisation’s administrator is removed by another administrator. Over the API it is GET and DELETE /api/v1/tenants/{tenant}/accounts/{id}/second-factor.

OAuth sign-in for JMAP apps

JMAP apps do not take your password at all. The app sends you to a page served by your mail server, you sign in and approve the app there, and the app receives a token that lets it read and send your mail. The tokens this server issues are for JMAP and the admin API.

Endpoints

All on the server’s host name, on port 443, whenever the store role runs:

EndpointPurpose
GET /.well-known/oauth-authorization-serverMetadata: the endpoints, grants and scopes this server supports.
GET /oauth/authorize, POST /oauth/authorizeThe authorisation-code flow: the Sign in page, and its answer.
POST /oauth/deviceStart the device flow: a code for the person, and a code for the app to poll with.
GET /oauth/device/approve, POST /oauth/device/approveThe Approve a device page, and its answer.
POST /oauth/tokenExchange an authorisation code, a device code or a refresh token for tokens.
POST /oauth/revokeGive up a refresh token, or an access token that is still valid. It ends the session the token belongs to. Always answers 200.
POST /oauth/introspectSay whether a token is still good, and what it is for (RFC 7662). See Checking a token.

Checking a token

An app can ask whether a token is still good by sending it to POST /oauth/introspect as a form field token, with an optional token_type_hint of access_token or refresh_token. The app proves who it is with an access token of its own, in an Authorization: Bearer header. Without one, or with one that is expired, revoked or not from this server, the answer is 401.

An app may ask only about tokens issued to it, for the same person. The answer for one of those that is still good has "active": true, with the token’s scope, client_id, sub (the person), exp, iat and iss. For any other token, whether expired, revoked, never issued or someone else’s, the answer is just {"active": false}, with no reason. Too many questions in a minute are answered 429 with Retry-After.

Services that check your people’s tokens

A service of your own that people reach with a Nixt Server token, such as an internal API or a gateway, can check any of your organisation’s tokens once you register it as a resource server. Your organisation’s administrators do this on the console, on the Webhooks page under Resource servers, or from the command line:

vsx admin resource-servers add 'Intranet gateway'
vsx admin resource-servers list
vsx admin resource-servers secret rs_4k2m9q7x1c8v3b6n
vsx admin resource-servers remove rs_4k2m9q7x1c8v3b6n

Adding one, or giving it a new secret, shows its id and secret once: store the secret in the service, since it cannot be shown again. A new secret ends the old one at once. Up to 25 can be registered.

The service sends POST /oauth/introspect with HTTP Basic authentication, the id as the user name and the secret as the password. It is told about any token of your organisation’s people, whichever app it was issued to, and {"active": false} for anything else, including another organisation’s tokens. A wrong id or secret is answered 401. Auditors can see the list; only the organisation’s administrators change it, and every change is in the audit log.

Flows

FlowUsed byHow it works
Authorisation code with PKCEDesktop and browser apps. Nixt Mail uses it with the system browser.The app opens /oauth/authorize in a browser. You sign in and choose Approve. The browser is sent back to the app with a code, which the app exchanges for tokens. PKCE with S256 is required.
Device codeApps that cannot open a browser.The app shows you a code and a link. You open the link on any device, sign in, check the code and choose Approve. The app polls until you have.
Refresh tokenEvery app, to stay signed in.The app exchanges its refresh token for new tokens.

Lifetimes

ItemLifetime
Access token1 hour
Refresh token30 days. Each use replaces it with a new one.
Authorisation code5 minutes, one use
Device code15 minutes. The app may poll every 5 seconds.

If an old refresh token that has already been replaced is used again, the server treats it as stolen and revokes every token descended from the same sign-in. Sign in again.

An organisation’s access rules can make a sign-in end sooner than thirty days, or when the browser it was made in closes.

Each sign-in is a session: the refresh tokens that descend from it, and every access token issued from them, which carries it as the sid claim. A session can be seen and ended on its own, by the person or an administrator, and the account’s other sessions carry on; see See and end one session. An ended session’s next request, and its next refresh, are refused.

Built-in applications

The server knows three applications. The sign-in pages show the application’s name, so you can check who is asking.

Name shownSigns in withMay ask for
versealx-mailThe authorisation-code flow, returning to the app on http://127.0.0.1 or http://[::1] on any port, or the device flowYour mail
versealx-cliThe device flow onlyYour mail
versealx-consoleThe authorisation-code flow, returning to the addresses in the runtime setting oauth.console.redirect_urisAccess to the admin API

A sign-in never grants an administrative role, whatever an application asks for. A request for one is refused with invalid_scope and the explanation <role> is a role, and a role is not granted for a password: administer this server with versealx-server admin over its local socket. See Roles and the audit log.

The sign-in pages

The server’s own pages load nothing from anywhere else and run no scripts. They follow your device’s light or dark appearance.

Approve a device

The page at https://mail.example.com/oauth/device/approve, which an app sends you to during the device flow.

  1. Check the code shown in large letters matches the code the app is showing. If you followed a link, it is filled in; otherwise type it into Code. Codes are eight letters, shown with a hyphen in the middle, and are not case-sensitive.
  2. Read the line that says which application is asking and for what — for example versealx-cli is asking for your mail.
  3. Enter your Email address and Password.
  4. Choose Approve to let the device in, or Deny to refuse.
You seeMeaning
Approved — The device can sign in now. You can go back to your terminal and close this page.The app receives its tokens at its next poll.
Refused — Nothing was granted, and that code will not work again. If you were not expecting this, nobody got in — but somebody asked.The app is told access was denied.
that code has run out. Start again in your terminal and you will get a new one.The code is older than 15 minutes.
that code is not one this server is waiting on. Check it, or start again in your terminal.A mistyped or already-used code.
that address and password did not matchThe address is unknown or the password is wrong. The page does not say which.
an address and a password are neededA field was left empty.
that account is not usableThe account cannot sign in, for example because it is disabled.
a code is neededThe form was sent without a code.
Choose a new passwordThe password is right, but it must be replaced before you approve anything. See Choosing a new password.
Your organisation does not allow signing in to this appYour organisation’s access rules do not allow this app, or what it asks for from where you are. Nothing was granted.

Sign in

The page an app opens during the authorisation-code flow. It shows which application is asking and for what, with Email address and Password fields and Approve and Deny buttons. Choosing Deny sends you back to the app with access_denied.

You seeMeaning
that address and password do not matchThe address is unknown or the password is wrong.
an address and a password are neededA field was left empty.
that account is not usableThe account cannot sign in.
Choose a new passwordThe password is right, but it must be replaced before it signs you in. See Choosing a new password.
Your organisation does not allow signing in to this appYour organisation’s access rules do not allow this app, or what it asks for from where you are.

Choosing a new password

A password that is right can still have to be replaced before it signs you in on these pages. That happens when an administrator set it for you and asked you to choose your own, or when it has appeared in a data breach since it was set. The page then shows Choose a new password and says which of the two it is.

  1. If your account has a second step, take it first. The page asks for the new password after it.
  2. Type the new password in New password, and again in The new password again.
  3. Choose Change password.

The new password must follow your organisation’s rules for passwords, must not be the one it replaces, and must not have appeared in a data breach when your organisation refuses leaked passwords. Once it is set, you are signed out everywhere else, and what you were doing carries on: the app gets its sign-in, the device is approved, or your quarantine opens. Mail apps that use your password will ask for the new one. The change is a line in the organisation’s audit log, never with the password.

You seeMeaning
Type your new password in both boxes.A box was left empty.
The two passwords are not the same. Type your new password in both boxes again.The two boxes differ.
That is the password you signed in with. Choose a new one.The new password is the one being replaced.
Your new password must be at least 14 characters.The new password breaks one of the rules for passwords. The page says which.
That sign-in has run out, or it took too many tries. Go back to where you started and sign in again.The page waits ten minutes, and takes five refused passwords.
Your password was changed while this page waited. Go back to where you started and sign in with the one you have now.Somebody else changed the password in the meantime, so this sign-in cannot choose the next one.

Cannot sign in

When a request cannot safely be sent back to the application that made it, the server shows Cannot sign in with the reason and the line Nothing was sent back to the application: this server will only return an answer to an address that application registered.

ReasonCause
no application is registered as "<name>"The app named an application the server does not know.
that application did not register the address it asked to be sent back toThe return address is not one registered for that application. For versealx-console, add it to oauth.console.redirect_uris.
this server could not read which applications it has registered. Try again.The store did not answer.

Problems that are the application’s own — a missing PKCE challenge, an unsupported response type, a scope it may not ask for — are sent back to the application as an OAuth error instead.

Forgotten passwords

By default, somebody who forgets their password asks an administrator to reset it. An organisation can let people recover their own account instead, through a recovery address they set beforehand.

Turning it on

On the console, Settings has an Account recovery card. From the command line:

vsx admin org account-recovery on
vsx admin org account-recovery off

A recovery address is a second way into each account that has one: whoever can read that mailbox holds half of it. The console asks you to confirm this before turning recovery on. Turning it off stops every recovery at once; the addresses people set are kept but not used.

Setting a recovery address

A person sets their address in the Recovery address section of Sign-in and security, at https://<your server>/account/second-factor. It must be an address outside the organisation, such as a personal one. They confirm with their password (and their second step, if they have one), and a code sent to the new address proves it is theirs. Changing it tells the old address, and every change is told to the account’s own mailbox.

Administrators can see whether somebody has set one, never what it is. On the console, that is the Recovery address card on the person’s page:

vsx admin people recovery-address ada@example.com

Recovering

Forgot your password? on the sign-in pages asks for the account’s address, sends an eight-digit code to its recovery address, and asks for the code and a new password.

  • The code is good for fifteen minutes and once. At most three are sent a day. A wrong one counts against the account and the network, as a wrong password does in the lockout.
  • The second step is asked too, where the account has one: Use your passkey as the second step once the emailed code is typed, a code from the authenticator app, or one of its recovery codes. A stolen recovery mailbox alone is not enough.
  • The new password follows the organisation’s password rules, and is checked against leaked passwords.
  • Asking reveals nothing. The page says a code is on its way whatever the address, whether or not it exists or has a recovery address.

Once done, the person is signed out everywhere, their own mailbox and the recovery address are told, and the organisation’s administrators get the account-recovered alert. It is also a line in the audit log, which never holds the password, the code or the recovery address.

Administrators are never recovered this way. An account with any administrative role, built-in or one the organisation made, cannot set a recovery address or be recovered; another administrator resets its password.

Signing in at your own identity provider

If your organisation has an identity provider, your people can sign in there instead of keeping a second password here — see Single sign-on.

Something unclear or out of date on this page? Tell us.