Two-Step Authentication
Overview
Two-step authentication — also called two-factor authentication, 2FA, or multi-factor authentication (MFA) — adds a second check to sign-in. After your password is accepted you are asked for a 6-digit code before you reach the application — so a stolen password on its own is not enough to get into your account.
It applies to accounts that sign in with a password. If your organisation uses Google or Microsoft sign-in, your second factor is handled by that identity provider instead and nothing here changes for you.
Signing in
Once two-step authentication is switched on, every sign-in asks for a code — there is no "remember this device".
You can choose either method each time:
| Option | Where the code comes from |
|---|---|
| Authenticator | The 6-digit code shown in your authenticator app, which changes every 30 seconds |
| Email me a code | A code sent to the email address on your account |
Worth knowing: unless your administrator has turned it off, a code can be emailed instead, so anyone who can read your email and knows your password can sign in. Treat access to your mailbox as being as sensitive as your DataDios password. See For administrators.
If you cannot use either, select Use a recovery code and enter one of the codes you saved during setup.
Setting it up
The first time you sign in after your administrator enables it, setup happens straight away — you cannot skip it.
- Confirm it's you. A 6-digit code is emailed to the address on your account. Enter it. This step proves the account is yours before an authenticator is attached to it. (Some installations have this step switched off and go straight to the QR code.)
- Scan the QR code with an authenticator app. Any TOTP app works — Google Authenticator, Microsoft Authenticator, Authy, 1Password, Bitwarden and others. If the QR will not scan, use Copy setup key and type the key into your app by hand.
- Enter the 6-digit code your app now shows, to confirm it is working.
- Save your recovery codes. See below — this step matters.
If setup cannot be started, the screen says "We couldn't start setup — try again to get your QR code" and offers a Try again button. Use it rather than going back and signing in again: the emailed code from step 1 can only be used once, so starting over means waiting for a new one.
Recovery codes
After setup you are shown a set of one-time recovery codes.
They are shown once and cannot be retrieved later. Copy or download them before continuing, and keep them somewhere separate from your phone — a password manager, or printed and stored securely. They are the only way back into your account if you lose your authenticator.
Each code works once. Using one signs you in but does not replace your authenticator app.
Occasionally setup finishes but signing you in does not, and the screen says "Two-step authentication is now on, but we couldn't finish signing you in." Two-step authentication is active on your account at that point, and the recovery codes on that screen are still the only set you will be given — save them, then sign in again with your authenticator as normal.
If you lose your authenticator
- You still have your recovery codes — sign in with one. You will have one fewer afterwards.
- You have lost both — you cannot get back in on your own. Contact your administrator, who can reset two-step authentication on your account so you can set it up again from scratch.
There is currently no self-service reset. If you are running low on recovery codes, ask your administrator to reset your two-step authentication so you can enrol again and receive a fresh set.
If your code is not accepted
"That code isn't valid. Please try again." Three usual causes:
- Your phone's clock is off. These codes are generated from the current time, so a clock a few minutes out produces codes DataDios will reject. Set your phone to update the time automatically.
- You are reading the wrong entry in your authenticator app.
- You submitted the same code twice. A code is accepted once and then refused, even while it is still showing on your phone — so a double-click on Continue counts the second press as a wrong code. Wait for the next one rather than retyping.
"Too many incorrect codes. Please try again later." After 6 wrong codes the second factor locks for 30 minutes, and during the lock even a correct code is refused. Two things to know:
- Wrong codes entered during setup count toward the same 6.
- When the 30 minutes are up you get one attempt, not a fresh six — the count only resets once you sign in successfully (or finish the emailed ownership check during setup). If that attempt is also wrong, it locks again for another 30 minutes.
During the lock nothing gets you in — a recovery code is refused as well. Either wait out the 30 minutes, or ask your administrator to reset your two-step authentication, which clears the lock at the same time.
Signing in also has a time limit of its own: once your password is accepted you have 5 minutes to finish the second step. Take longer and you simply start again from the password screen — it is not a lockout and it costs you nothing.
For administrators
Two-step authentication is configured through environment variables on the deployment, so these are
set wherever your .env or docker-compose file lives. The application's own default for
MFA_ENABLED is false, but every DataDios-supplied compose file sets it to true, so a standard
deployment has the feature live unless you set MFA_ENABLED=false yourself. MFA_REQUIRED_ROLES
works the same way: the application default is empty, meaning nobody is forced to enrol, and the
supplied compose files set *, meaning everyone is. So on a standard deployment every password
account is asked to set up an authenticator at its next sign-in. Both columns below are the
application's defaults — check your own compose file for what is actually set.
| Setting | Default | What it does |
|---|---|---|
MFA_ENABLED | false | Master switch. While false the feature behaves as though it is not installed. |
MFA_REQUIRED_ROLES | (empty) | Who is required to set it up: empty = nobody, * = everyone, or a comma-separated list of user types. The accepted names are Admin, Normal (see Resource Center) and Privileged (Privileged comes from the PRIVILEGED_USER_EMAIL environment variable — a comma-separated list of privileged account emails). Matching is exact and case-sensitive, so admin forces nobody. A value that matches no user type is reported at startup — the server logs a warning naming it and listing the valid values — so check the boot log after changing this. |
MFA_EMAIL_LOGIN_CODE_ENABLED | true | Whether Email me a code is offered as an alternative to the authenticator at sign-in. Set false to require the authenticator — see Two things to be aware of. |
MFA_ENROLL_EMAIL_VERIFICATION | true | Whether the emailed ownership check runs before setup. |
MFA_EMAIL_CODE_TTL_MINUTES | 10 | How long an emailed code stays valid. |
MFA_EMAIL_CODE_RESEND_SECONDS | 30 | Minimum gap between two emailed codes for one account, so the send step cannot be used to flood a mailbox. |
MFA_PENDING_TOKEN_TTL_MINUTES | 5 | How long a user has to finish the second step after their password is accepted. |
MFA_RECOVERY_CODE_COUNT | 8 | How many one-time recovery codes are issued at setup. Anything outside 1–20 is ignored and 8 is used; the server logs a warning at startup. |
MFA_ISSUER_NAME | DataDios | The name shown next to the account in the user's authenticator app. |
MFA_EXEMPT_EMAILS | (empty) | Comma-separated email addresses to exempt from two-step authentication, in addition to the built-in accounts — see Two things to be aware of. |
MFA_EXEMPT_TEST_ACCOUNTS | false | When true, exempts the seeded pytest/Playwright test addresses from two-step authentication. Only test compose files should set this — never turn it on for a customer deployment. |
Sending mail
Enrolment emails an ownership code, and Email me a code delivers a sign-in code, so both depend on the deployment being able to send mail. DataDios sends through the Microsoft Graph API only — there is no SMTP option — using four environment variables:
| Variable | What it is |
|---|---|
AZURE_TENANT_ID | The Entra ID (Azure AD) tenant the sending app registration lives in. |
AZURE_CLIENT_ID | That app registration's client id. |
AZURE_CLIENT_SECRET | Its client secret. |
SENDER_EMAIL | The mailbox mail is sent as. It must be a licensed mailbox in the same tenant. |
The app registration needs the Mail.Send application permission, granted with admin consent —
mail is sent with client credentials, not on behalf of a signed-in user.
If your deployment has no Entra tenant to send from, set MFA_ENROLL_EMAIL_VERIFICATION=false so
enrolment goes straight to the QR code. Users will not be able to receive a sign-in code either, so
make sure they save their recovery codes.
Suggested rollout
- Set
MFA_ENABLED=trueand leaveMFA_REQUIRED_ROLESempty. The feature is live but nobody is forced into it yet. - Walk two or three users through setup and confirm the emails arrive.
- Confirm you can reset a user who has genuinely lost their device.
- Set
MFA_REQUIRED_ROLESto the roles you want covered.
Emptying MFA_REQUIRED_ROLES is a complete rollback — nobody new is asked to set it up, and
users who already have it keep working.
Resetting a user
If a user loses both their authenticator and their recovery codes, reset them so they can enrol again:
POST /admin/users/<user_id>/mfa/reset
This requires an administrator session. There is no screen for it yet, so it is run against the API directly. The action is recorded in the server log with both who performed it and who it was performed on.
Checking whether a user has it set up
DataDios has no admin view of enrolment status today — the user list does not show who has set up an authenticator. In practice you find out when a user tells you, either that they are being asked for a code or that they cannot get in. If you need certainty before enforcing a policy, ask the user to confirm they have completed setup and saved their recovery codes.
Resetting a user is safe either way: a user who has never enrolled is unaffected, and one who has is simply asked to set up again at their next sign-in.
Two things to be aware of
Email as a second factor. Because Email me a code is offered at every sign-in by default, an account's second factor is only as strong as the mailbox behind it — and for a password account that mailbox is already the password's own reset channel, so someone holding it can reach both factors. This is a deliberate default, chosen because against the far more common attack — a stolen or reused password with no mailbox access — the emailed code is a real second factor, and it gives a user whose phone is unavailable a way in that does not need an administrator.
What it means for a compliance claim: the deployment offers password + (authenticator or
email), not password + authenticator. If you need the stricter one, set
MFA_EMAIL_LOGIN_CODE_ENABLED=false. The button then disappears from the sign-in screen and only
the authenticator (or a recovery code) is accepted. This is separate from
MFA_ENROLL_EMAIL_VERIFICATION, which points the other way — it strengthens setup — and should
stay on.
Built-in accounts are exempt. The default administrator and the internal scheduler account are never asked for a second factor — DataDios checks their email address against a fixed exemption list, not their role, so this does not extend to any account you create yourself. The scheduler signs in programmatically and would break, and the default administrator is the account used to administer the platform. Everyday administrators should use their own named accounts, which are not exempt.
If your deployment runs a test or demo stack from the bundled test compose files, note that those
files set MFA_EXEMPT_TEST_ACCOUNTS=true, which exempts the twelve seeded automation accounts.
It is off by default and nothing else turns it on — a deployment that never sets it exempts only
the two built-in accounts above.
An on-prem deployment can exempt its own service accounts the same way, with a comma-separated list of email addresses:
MFA_EXEMPT_EMAILS=service-account@example.com,another-bot@example.com
Use this only for accounts that authenticate programmatically, the same way the scheduler does — not as a way to skip setup for a person.
If your deployment cannot send email, set both MFA_ENROLL_EMAIL_VERIFICATION=false and
MFA_EMAIL_LOGIN_CODE_ENABLED=false. Setup then goes straight to the QR code, and Email me a
code is not offered at sign-in. Note this accepts a trade-off: without the emailed check, whoever
signs in first with a valid password is the one who attaches an authenticator to that account.
Only use it where email genuinely is not available. Turning off only the enrolment check leaves
the sign-in button visible and every press fails.