# Two-Factor Authentication

> Protect dashboard sign-in with an authenticator app, require it for every user on the installation, sign users in automatically from Cloudflare Access, and recover when an administrator is locked out.

Source: https://sendbroadcast.net/docs/two-factor-authentication

A password alone is a weak lock on a tool that can email your whole list. Broadcast supports a
second sign-in step with an authenticator app, lets an administrator require it for everyone, and
can hand sign-in over to Cloudflare Access entirely if the dashboard already sits behind it.

Three pieces, each usable on its own:

- **Authenticator app (TOTP)**: each user enrols from their profile and signs in with a password
  plus a six-digit code. Works offline with 1Password, Google Authenticator, Authy, Microsoft
  Authenticator, or any app that scans a QR code.
- **Enforcement**: an installation-wide switch that makes two-factor mandatory, with a grace
  period so existing users are reminded before they are locked out.
- **Cloudflare Access sign-in**: users who reach the dashboard through a Cloudflare Access
  application are signed in automatically, with no Broadcast password and no code.

Note

None of this touches the API. Tokens keep working exactly as before, and requiring two-factor for users does not affect integrations or the SDKs.

## Enrolling as a user

Open **My Profile**. The **Two-factor authentication** section shows whether it is on for your
account.

![The two-factor authentication section of My Profile, showing Not enabled and a Set up button](https://sendbroadcast.net/assets/docs/two-factor-authentication/profile-two-factor-section-dc270570.png)

1. Click **Set up**.
2. Scan the QR code with your authenticator app. If you cannot scan, type the key shown next to
   it into the app by hand.
3. Enter the six-digit code the app now shows and click **Enable two-factor authentication**.

![Enrolment page with a QR code, the manual entry key, and a field for the six-digit code](https://sendbroadcast.net/assets/docs/two-factor-authentication/enrolment-qr-code-0fbccc39.png)

4. Save the **ten recovery codes** that appear. They are shown once. Each one signs you in a
   single time if you lose your device. **Copy codes** puts them on your clipboard.

![Ten recovery codes shown once after enrolment, with Copy codes and Done buttons](https://sendbroadcast.net/assets/docs/two-factor-authentication/recovery-codes-20ec1815.png)

From the next sign-in on, Broadcast asks for a code after your password. Codes are valid for
thirty seconds, with a little tolerance for a phone whose clock drifts. A code that has already
been used is refused even inside that window.

### Recovery codes

If your authenticator is gone, enter a recovery code in place of the six-digit code. Broadcast
tells you how many remain. Generate a fresh set from **My Profile → Manage** at any time; doing so
invalidates every code from the old set.

### Turning it off

From **My Profile → Manage**, confirm with your current password and a live code. Both are
required so that a session left open on a shared machine cannot quietly weaken the account.

![The manage page for an enrolled user: status, generate new recovery codes, and disable two-factor authentication](https://sendbroadcast.net/assets/docs/two-factor-authentication/manage-two-factor-71a6ae03.png)

### Wrong codes

Wrong codes count against the same limit as wrong passwords. After five failures in a row the
account is locked and shows as inactive. An administrator reactivates it with **Activate User**
on the user's page under **Users**, which also clears the failure count. Broadcast additionally
limits how many codes one IP address can try per minute, so a wrong code retyped from a phone is
fine but a script is not. The limit is 10 attempts a minute; change it with the
`TWO_FACTOR_ATTEMPTS_PER_MINUTE` environment variable in `/opt/broadcast/app/.env`.

## If a user is locked out

A user who has lost their device and used up their recovery codes cannot get in on their own. An
administrator with user-management permission opens the user's page under **Users** and chooses
**Reset Two-Factor** from the actions menu. The user can then sign in with their password alone
and enrol again.

![A user's page under Users with the actions menu open, showing Reset Two-Factor](https://sendbroadcast.net/assets/docs/two-factor-authentication/admin-reset-two-factor-eef1840d.png)

Your own two-factor cannot be reset from that page; it is managed from your profile, with the
password and code checks above.

## If the administrator is locked out

The reset above needs someone who can sign in. When there is nobody, because the only
administrator lost their authenticator and every recovery code, or because two-factor was made
mandatory before anyone able to switch it off had enrolled, the way back is the command line on
the server. On an automatic installation:

```bash
cd /opt/broadcast

# Clear one user's authenticator and recovery codes. They sign in with their
# password alone and can enrol again from their profile.
./broadcast.sh two_factor reset admin@example.com

# Stop requiring two-factor for everyone. Users who already enrolled keep it.
./broadcast.sh two_factor disable_enforcement

# See whether two-factor is required and who has it enabled.
./broadcast.sh two_factor status
```

Broadcast must be running, since the command works inside the app container. On a manual Docker
installation, run the same tasks directly:

```bash
docker exec -it app bin/rails "two_factor:reset[admin@example.com]"
docker exec -it app bin/rails two_factor:disable_enforcement
docker exec -it app bin/rails two_factor:status
```

Warning

Anyone with a shell on the server can run these, which is as it should be: a person who controls the machine controls the database too. Treat server access with the same care as the administrator password. See [CLI Reference](https://sendbroadcast.net/docs/cli-reference) for the other commands.

## Requiring two-factor for everyone

Under **Application → Security**, tick **Require two-factor authentication for all users** and
pick a grace period: enforce immediately, or give existing users 7, 14 or 30 days.

![Security settings with two-factor required, a 7 day grace period, and the enforcement date shown](https://sendbroadcast.net/assets/docs/two-factor-authentication/security-two-factor-5364dca8.png)

- During the grace period every user who has not enrolled sees a banner on each page naming the
  deadline, with a link to enrolment.

![Banner at the top of the dashboard: two-factor authentication will be required from a date, with a link to set it up](https://sendbroadcast.net/assets/docs/two-factor-authentication/grace-period-banner-1c15aeb3.png)

- Once the deadline passes, a user without two-factor is sent to enrolment on every request and
  can do nothing else in the dashboard until they finish. They can still sign out.
- The requirement applies to every user, administrators included. There is no exempt account.
- A grace period that is already running is never extended by saving the page again, so you can
  adjust other settings without moving the deadline.

The page also shows how many users have enrolled so far, which is worth checking a day or two
before the deadline.

Warning

Before you enforce immediately, make sure at least one user with user-management permission has enrolled. Enforcement is unconditional, and the only way past it from the dashboard is to enrol. If you do lock everyone out, `./broadcast.sh two_factor disable_enforcement` on the server turns the requirement off again.

## Cloudflare Access sign-in

Many teams already put internal tools behind [Cloudflare Access](https://developers.cloudflare.com/cloudflare-one/policies/access/),
which is free for up to fifty users and handles one-time PINs, Google or Microsoft sign-in, and
hardware keys. Broadcast can trust it: when a request arrives through your Access application,
Cloudflare attaches a signed assertion naming the user, and Broadcast signs in the Broadcast
user with that email. No password, and no authenticator code, because Cloudflare has already
done the second factor.

### Setting it up

1. In the Cloudflare Zero Trust dashboard, create a self-hosted **Access application** for the
   dashboard's hostname, with whatever policy your team needs.
2. Note two values: your **team domain** (Settings → Custom Pages, in the form
   `yourteam.cloudflareaccess.com`) and the application's **Audience (AUD) tag** (Access →
   Applications → your application → Overview).
3. In Broadcast, under **Application → Security → Cloudflare Access sign-in**, tick **Sign
   users in from Cloudflare Access**, enter both values, and save.

![Cloudflare Access sign-in settings: enable toggle, team domain, audience tag, access-only toggle, and a Check this request button](https://sendbroadcast.net/assets/docs/two-factor-authentication/security-cloudflare-access-b6a90db3.png)

4. Open the Security page again *through the Access application* and click **Check this
   request**. Broadcast reports the email Cloudflare verified, or explains what was wrong with
   the assertion.

Users must exist in Broadcast with the same email address Cloudflare knows them by. Someone who
passes Access but has no Broadcast user sees the normal login page with a note saying so; Broadcast
does not create accounts from Access.

### Locking the origin down

Cloudflare can only vouch for requests that actually pass through it. If the server is
reachable directly by IP, or on another hostname, a visitor can skip Access and reach the
password form. Two ways to close that:

- Publish the dashboard through a [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/),
  so the origin has no public inbound port at all. This is the recommended setup.
- Or allow inbound traffic only from [Cloudflare's IP ranges](https://www.cloudflare.com/ips/)
  at the firewall.

Once the origin is closed, you can tick **Disable password sign-in (Cloudflare Access only)**.
The password form disappears and password sign-ins are refused, so Access becomes the only door.
Broadcast only lets you turn this on from a request that itself came through Access, which
prevents a typo in the audience tag from locking you out of your own installation.

Note

Cloudflare Access sign-in and two-factor enforcement work together. A user who signs in through Access skips the code even if enforcement is on, because Cloudflare performed the second factor. Anyone still signing in with a password is held to the requirement.

## Which one should you use?

| Situation | Use |
|---|---|
| Any installation, any size | Authenticator app, enrolled per user |
| A team that must all have a second factor | Authenticator app plus enforcement |
| Dashboard already behind Cloudflare Access | Cloudflare Access sign-in, with the origin locked down |
| Clients who insist on their own identity provider | Cloudflare Access can federate to Google, Microsoft, Okta and others, then sign the user into Broadcast |

See also [Users & Permissions](https://sendbroadcast.net/docs/users-and-permissions) for who can change these settings, and
[CLI Reference](https://sendbroadcast.net/docs/cli-reference) for the recovery commands.
