discourse/app/controllers/admin
Keegan George f4bd916c88
FEATURE: Log in with a one-time email code (#40804)
Previously, the only passwordless way to log in by email was a one-click
magic link, enabled with `enable_local_logins_via_email`.

This change adds `enable_local_logins_via_code`, which switches that
flow to send a short one-time code instead of a link: when enabled, the
login page offers "Email me a one-time login code" in place of the link
option, and entering the emailed code logs the user in (including
through any configured second factor). A code only ever logs an
*existing* user in, and the request endpoint responds identically
whether or not the email matches an account, so it can't be used to
probe for accounts.

Signing up with a one-time code builds on this and is in #40909.

<details>
<summary>Screenshots</summary>

**Desktop**

| Step | Foundation · Light | Foundation · Dark | Horizon · Light |
Horizon · Dark |
|---|---|---|---|---|
| Password form (default) | <img width="1400" height="1200"
alt="desktop-foundation-light-code-login-password-form"
src="https://github.com/user-attachments/assets/aa6758f0-9402-4229-8ad8-962d9773b7bd"
/> | <img width="1400" height="1200"
alt="desktop-foundation-dark-code-login-password-form"
src="https://github.com/user-attachments/assets/e4283e80-5973-48ba-8b24-e4a154fd04ea"
/> | <img width="1400" height="1200"
alt="desktop-horizon-light-code-login-password-form"
src="https://github.com/user-attachments/assets/8b58915c-f040-40cf-aa28-50e763032ba1"
/> | <img width="1400" height="1200"
alt="desktop-horizon-dark-code-login-password-form"
src="https://github.com/user-attachments/assets/4de1c283-1021-4ac1-b4e1-9e5e14a1a883"
/> |
| Email entry | <img width="1400" height="1200"
alt="desktop-foundation-light-code-login-email-step"
src="https://github.com/user-attachments/assets/9ecd42cd-b7a4-4eaa-b7a4-f3de2418d7df"
/> | <img width="1400" height="1200"
alt="desktop-foundation-dark-code-login-email-step"
src="https://github.com/user-attachments/assets/6e2d106c-6fdd-498b-a470-85b5dafab2c7"
/> | <img width="1400" height="1200"
alt="desktop-horizon-light-code-login-email-step"
src="https://github.com/user-attachments/assets/adfc7f9b-2651-43e1-a2ab-b37d1ff3e34f"
/> | <img width="1400" height="1200"
alt="desktop-horizon-dark-code-login-email-step"
src="https://github.com/user-attachments/assets/4e6872e1-ce77-462d-a04f-2c81fa5e61ed"
/> |
| Code entry | <img width="1400" height="1200"
alt="desktop-foundation-light-code-login-code-step"
src="https://github.com/user-attachments/assets/b9b53768-e095-489a-bb62-d23e8b018d28"
/> | <img width="1400" height="1200"
alt="desktop-foundation-dark-code-login-code-step"
src="https://github.com/user-attachments/assets/933e41fb-ea1b-434e-87b7-ffca6d651628"
/> | <img width="1400" height="1200"
alt="desktop-horizon-light-code-login-code-step"
src="https://github.com/user-attachments/assets/936967cf-b657-4d9f-80e2-c44226b681c3"
/> | <img width="1400" height="1200"
alt="desktop-horizon-dark-code-login-code-step"
src="https://github.com/user-attachments/assets/2bf4530c-e6ba-4561-963e-36a494288c3c"
/> |
| Invalid code | <img width="1400" height="1200"
alt="desktop-foundation-light-code-login-wrong-code"
src="https://github.com/user-attachments/assets/ddaf1ae4-66ec-499b-859c-c169ce544f3d"
/> | <img width="1400" height="1200"
alt="desktop-foundation-dark-code-login-wrong-code"
src="https://github.com/user-attachments/assets/f6a57236-f498-4a98-ac80-aee3f7a1e1a5"
/> | <img width="1400" height="1200"
alt="desktop-horizon-light-code-login-wrong-code"
src="https://github.com/user-attachments/assets/e8622433-d693-4faf-b2aa-f71c910c3b52"
/> | <img width="1400" height="1200"
alt="desktop-horizon-dark-code-login-wrong-code"
src="https://github.com/user-attachments/assets/0221c9ba-5003-4160-9ef9-281045f2f318"
/> |

**Mobile**

| Step | Foundation · Light | Foundation · Dark | Horizon · Light |
Horizon · Dark |
|---|---|---|---|---|
| Password form (default) | <img width="1170" height="3600"
alt="mobile-foundation-light-code-login-password-form"
src="https://github.com/user-attachments/assets/6e25f7b4-915f-4f55-8b27-9f51ec4ec1ea"
/> | <img width="1170" height="3600"
alt="mobile-foundation-dark-code-login-password-form"
src="https://github.com/user-attachments/assets/0e1b0009-8b70-454f-8167-01c7a8ce0664"
/> | <img width="1170" height="3600"
alt="mobile-horizon-light-code-login-password-form"
src="https://github.com/user-attachments/assets/79949635-a8f5-4fc5-aa2f-22edb77f7b2d"
/> | <img width="1170" height="3600"
alt="mobile-horizon-dark-code-login-password-form"
src="https://github.com/user-attachments/assets/1f7e962d-5e0b-4e22-bb54-0b27b870696f"
/> |
| Email entry | <img width="1170" height="3600"
alt="mobile-foundation-light-code-login-email-step"
src="https://github.com/user-attachments/assets/5577aad2-dd30-4424-af7a-af5f33458c8c"
/> | <img width="1170" height="3600"
alt="mobile-foundation-dark-code-login-email-step"
src="https://github.com/user-attachments/assets/571b5bf2-0b07-46ec-ba3a-b80bc1078643"
/> | <img width="1170" height="3600"
alt="mobile-horizon-light-code-login-email-step"
src="https://github.com/user-attachments/assets/3beb6702-e7df-434b-98d6-23203c6bee98"
/> | <img width="1170" height="3600"
alt="mobile-horizon-dark-code-login-email-step"
src="https://github.com/user-attachments/assets/17b33dc8-c133-4f07-8817-1f1f7c6cf8ff"
/> |
| Code entry | <img width="1170" height="3600"
alt="mobile-foundation-light-code-login-code-step"
src="https://github.com/user-attachments/assets/91beeec5-87eb-4169-a53d-53164dd7dd2a"
/> | <img width="1170" height="3600"
alt="mobile-foundation-dark-code-login-code-step"
src="https://github.com/user-attachments/assets/8d8de095-7050-4006-bc72-6a82f7c17513"
/> | <img width="1170" height="3600"
alt="mobile-horizon-light-code-login-code-step"
src="https://github.com/user-attachments/assets/f874a1c6-2e9f-4c0c-b500-850c44067489"
/> | <img width="1170" height="3600"
alt="mobile-horizon-dark-code-login-code-step"
src="https://github.com/user-attachments/assets/4957797c-00e9-45b8-8504-8baba15cde06"
/> |
| Invalid code | <img width="1170" height="3600"
alt="mobile-foundation-light-code-login-wrong-code"
src="https://github.com/user-attachments/assets/76124aa6-fd77-467a-b1bb-60e85e354612"
/> | <img width="1170" height="3600"
alt="mobile-foundation-dark-code-login-wrong-code"
src="https://github.com/user-attachments/assets/c0f8d7db-9a7e-4803-928c-91a504bf8391"
/> | <img width="1170" height="3600"
alt="mobile-horizon-light-code-login-wrong-code"
src="https://github.com/user-attachments/assets/77b97702-8ee7-4244-906e-6fddb5e22cae"
/> | <img width="1170" height="3600"
alt="mobile-horizon-dark-code-login-wrong-code"
src="https://github.com/user-attachments/assets/e034b400-6430-4441-9b2a-c0f1b0bb49c6"
/> |
</details>
2026-06-17 12:34:48 -07:00
..
config UX: Organization website field (#40418) 2026-06-04 09:32:19 -07:00
admin_controller.rb DEV: Drop WithServiceHelper 2024-09-05 09:58:20 +02:00
admin_notices_controller.rb DEV: Update rubocop-discourse to 3.13 and autofix issues (#35073) 2025-10-06 16:11:01 +02:00
api_controller.rb DEV: Tidy plugin API key scope resource names (#38640) 2026-03-17 13:03:42 +11:00
backups_controller.rb DEV: Enable Rails/FilePath rubocop rule (#40097) 2026-05-19 19:07:54 +02:00
badges_controller.rb FIX: ensures admin can't set system property on badges (#37820) 2026-02-16 12:33:32 +01:00
color_schemes_controller.rb FEATURE: Allow editing theme-owned palettes (#34722) 2025-10-06 09:02:39 +03:00
dashboard_controller.rb PERF: Parallelize section loading in new dashboard (#40970) 2026-06-17 16:29:10 +08:00
email_controller.rb DEV: Fix job serialization deprecation in email controller (#39311) 2026-04-16 11:42:34 +02:00
email_logs_controller.rb DEV: Update rubocop-discourse to 3.13 and autofix issues (#35073) 2025-10-06 16:11:01 +02:00
email_styles_controller.rb
email_templates_controller.rb FEATURE: Log in with a one-time email code (#40804) 2026-06-17 12:34:48 -07:00
embeddable_hosts_controller.rb DEV: Expand top_tags, topic.tags, etc, to return an array of tag objects instead of tag names (#36678) 2026-02-02 10:03:02 +08:00
embedding_controller.rb DEV: Enable Style/RedundantParentheses rubocop rule (#40095) 2026-05-19 15:48:09 +02:00
emoji_controller.rb DEV: Move admin config pages out of /customize/ sub-route (#30511) 2025-01-02 09:13:11 +10:00
form_templates_controller.rb FIX: Form templates page returning 500 error (#39799) 2026-05-06 18:53:52 +02:00
groups_controller.rb DEV: Add descriptive error message when creating requestable group with no owner (#40391) 2026-05-29 11:11:59 +08:00
impersonate_controller.rb FEATURE: Impersonation countdown (#39871) 2026-05-12 12:12:25 +08:00
permalinks_controller.rb DEV: Enable Style/RedundantParentheses rubocop rule (#40095) 2026-05-19 15:48:09 +02:00
plugins_controller.rb FIX: Don't allow access to plugin page if plugin is not visible (#26431) 2024-04-02 16:26:15 +03:00
problem_checks_controller.rb FEATURE: Add problem checks page to admin panel and allow ignoring problem checks (#39103) 2026-04-23 08:28:33 +08:00
reports_controller.rb FIX: Suspicious login IPs bypass the moderator IP-visibility setting (#40154) 2026-05-22 13:22:32 +08:00
robots_txt_controller.rb FIX: Log changes to robots.txt by admins (#37901) 2026-02-18 14:20:21 -05:00
screened_emails_controller.rb SECURITY: Moderators cannot see user emails. 2024-12-19 13:13:18 -03:00
screened_ip_addresses_controller.rb DEV: Require admin for allow_admin screened IP mutations (#38545) 2026-03-12 10:43:19 -07:00
screened_urls_controller.rb
search_controller.rb DEV: Rename anonymous group to anonymous_users (#40435) 2026-06-02 09:29:46 +10:00
search_logs_controller.rb
section_controller.rb DEV: Add a skeleton for section landing page & items (#28477) 2024-10-02 12:19:38 +10:00
site_settings_controller.rb FEATURE: onboarding banner for admins (#37583) 2026-02-10 14:53:44 -03:00
site_texts_controller.rb UX: Don't include powered_by string in site text overrides (#39660) 2026-04-30 12:15:34 -04:00
staff_action_logs_controller.rb DEV: Add comparison budget to ONPDiff (#38063) 2026-02-25 14:25:03 -05:00
staff_controller.rb DEV: Drop WithServiceHelper 2024-09-05 09:58:20 +02:00
themes_controller.rb DEV: Enable Style/RedundantBegin rubocop rule (#40096) 2026-05-19 18:44:54 +02:00
unknown_reviewables_controller.rb FEATURE: Gracefully handle unhandled reviewables (#31118) 2025-02-05 14:38:45 +11:00
user_fields_controller.rb DEV: Update rubocop (#38721) 2026-03-20 00:39:52 +01:00
users_controller.rb DEV: Enable Style/RedundantBegin rubocop rule (#40096) 2026-05-19 18:44:54 +02:00
versions_controller.rb
watched_words_controller.rb DEV: Deferred upload accesses tempfile after request completes (#38337) 2026-03-10 07:53:29 -07:00
web_hooks_controller.rb FIX: Allow selecting tags when creating or editing webhooks (#37942) 2026-02-20 23:00:50 +08:00