discourse/app/jobs/scheduled
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
..
about_stats.rb
activation_reminder_emails.rb
aggregate_web_hooks_events.rb DEV: Enable Style/RedundantParentheses rubocop rule (#40095) 2026-05-19 15:48:09 +02:00
auto_queue_handler.rb DEV: replace .each with .find_each for paginated queries (#27159) 2024-05-23 15:42:21 -07:00
backfill_dominant_colors.rb
backfill_nested_reply_stats.rb FEATURE: First iteration of nested replies (#38888) 2026-04-16 08:06:44 -05:00
badge_grant.rb DEV: Enable Style/RedundantSelf rubocop rule (#40098) 2026-05-19 19:27:45 +02:00
bookmark_reminder_notifications.rb
calculate_scores.rb DEV: Split weekly job into multiple smaller jobs (#31260) 2025-02-11 10:26:45 +02:00
call_discourse_hub.rb DEV: Enable Style/RedundantParentheses rubocop rule (#40095) 2026-05-19 15:48:09 +02:00
category_stats.rb
check_new_features.rb UX: suppress new feature notifications on brand new sites (#40135) 2026-05-19 09:38:57 +10:00
check_out_of_date_themes.rb
check_translation_overrides.rb FIX: Ensure JsLocaleHelper to not output deprecated translations (#28037) 2024-07-29 15:21:25 +08:00
check_upcoming_changes.rb FIX: Do not send notifications for upcoming changes not displayed (#40933) 2026-06-17 09:10:49 +10:00
clean_dismissed_topic_users.rb
clean_up_api_keys_max_life.rb FEATURE: site settings to revoke api keys older than a number of days (#23595) 2023-09-15 16:31:29 -03:00
clean_up_associated_accounts.rb
clean_up_associated_groups.rb
clean_up_bookmarks.rb DEV: Split weekly job into multiple smaller jobs (#31260) 2025-02-11 10:26:45 +02:00
clean_up_browser_pageview_events.rb FIX: Backfill normalized referrer for historical browser pageviews (#40357) 2026-06-09 09:04:57 +08:00
clean_up_crawler_stats.rb
clean_up_drafts.rb DEV: Split weekly job into multiple smaller jobs (#31260) 2025-02-11 10:26:45 +02:00
clean_up_email_change_requests.rb
clean_up_email_login_codes.rb FEATURE: Log in with a one-time email code (#40804) 2026-06-17 12:34:48 -07:00
clean_up_email_logs.rb
clean_up_email_tokens.rb
clean_up_exports.rb
clean_up_inactive_users.rb DEV: Enable Style/RedundantBegin rubocop rule (#40096) 2026-05-19 18:44:54 +02:00
clean_up_post_reply_keys.rb
clean_up_search_logs.rb
clean_up_stylesheet_cache.rb
clean_up_tags.rb FIX: sort tag names in clean up tags staff log entry (#37909) 2026-02-19 14:43:58 +08:00
clean_up_unmatched_emails.rb
clean_up_unmatched_ips.rb
clean_up_unsubscribe_keys.rb
clean_up_unused_api_keys.rb
clean_up_unused_registered_user_api_key_clients.rb DEV: Fix assigned but unused variable Prism warnings (#39436) 2026-04-22 12:42:14 +02:00
clean_up_unused_staged_users.rb DEV: Enable Style/RedundantBegin rubocop rule (#40096) 2026-05-19 18:44:54 +02:00
clean_up_unused_user_api_keys.rb FEATURE: site settings to revoke api keys older than a number of days (#23595) 2023-09-15 16:31:29 -03:00
clean_up_uploads.rb FIX: Clean up not secure uploads with access_control_post_id (#31189) 2025-02-06 11:26:34 +10:00
clean_up_user_api_keys_max_life.rb FEATURE: site settings to revoke api keys older than a number of days (#23595) 2023-09-15 16:31:29 -03:00
clean_up_user_auth_tokens.rb DEV: Split weekly job into multiple smaller jobs (#31260) 2025-02-11 10:26:45 +02:00
cleanup_problem_check_trackers.rb DEV: Clean up trackers with outdated targets (#35978) 2026-01-14 12:54:16 +01:00
cleanup_redelivering_web_hook_events.rb DEV: Update rubocop-discourse to 3.13 and autofix issues (#35073) 2025-10-06 16:11:01 +02:00
clear_expired_impersonations.rb DEV: Allow impersonation without session swapping (#34213) 2025-08-21 14:18:15 +08:00
create_missing_avatars.rb
create_recent_post_search_indexes.rb DEV: Deprecate the assignment of nil to site settings (#36093) 2025-12-01 15:04:23 +08:00
delete_rejected_emails.rb DEV: Split weekly job into multiple smaller jobs (#31260) 2025-02-11 10:26:45 +02:00
destroy_old_deletion_stubs.rb
destroy_old_hidden_posts.rb
detect_crawler_pageviews.rb DEV: Add anonymous pageview crawler scoring job (#39954) 2026-05-14 12:46:08 +08:00
directory_refresh.rb DEV: refresh user directory more often for sites with few users (#39852) 2026-05-08 12:04:03 -04:00
drop_backup_schema.rb
enqueue_digest_emails.rb FIX: send activity summaries based on "last seen" (#27035) 2024-05-22 10:23:03 +02:00
enqueue_onceoffs.rb
enqueue_suspect_users.rb FIX: Exclude suspended users from suspect users review queue (#37796) 2026-02-16 10:46:52 +08:00
ensure_badges_consistency.rb PERF: Enqueue Job::BackfillBadge in Jobs::BadgeGrant (#30945) 2025-01-24 09:35:01 +08:00
ensure_db_consistency.rb DEV: Rescue from each step of EnsureDbConsistency (#31313) 2025-02-13 12:07:04 +02:00
ensure_s3_uploads_existence.rb FIX: Jobs::EnsureS3UploadsExistence broken for multisite (#27401) 2024-06-10 16:26:39 +08:00
fix_user_usernames_and_groups_names_clash.rb DEV: Hand-pick Rails/WhereNot autofixes (#35117) 2025-10-03 13:29:22 +02:00
grant_anniversary_badges.rb
grant_new_user_of_the_month_badges.rb
heartbeat.rb FIX: Redo Sidekiq monitoring to restart stuck sidekiq processes (#30198) 2024-12-18 12:48:50 +08:00
ignored_users_summary.rb
invalidate_inactive_admins.rb
maintain_browser_pageview_rollups.rb FIX: Backfill normalized referrer for historical browser pageviews (#40357) 2026-06-09 09:04:57 +08:00
migrate_upload_scheme.rb
notify_admins_of_available_upcoming_changes.rb FIX: Do not send notifications for upcoming changes not displayed (#40933) 2026-06-17 09:10:49 +10:00
notify_admins_of_problems.rb FEATURE: Add problem checks page to admin panel and allow ignoring problem checks (#39103) 2026-04-23 08:28:33 +08:00
old_keys_reminder.rb DEV: Update rubocop-discourse to 3.13 and autofix issues (#35073) 2025-10-06 16:11:01 +02:00
pending_queued_posts_reminder.rb
pending_reviewables_reminder.rb FIX: rename notify_about_flags_after to notify_about_reviewable_item_after (#21320) 2023-05-02 08:08:22 +10:00
pending_users_reminder.rb Revert "FEATURE: discourse-workflows (#39704)" (#40366) 2026-05-28 13:59:42 +01:00
periodical_updates.rb DEV: Enable Style/RedundantParentheses rubocop rule (#40095) 2026-05-19 15:48:09 +02:00
poll_mailbox.rb DEV: Database backed admin notices (#26192) 2024-05-23 09:29:08 +08:00
presence_channel_auto_leave.rb
process_badge_backlog.rb
process_shelved_notifications.rb
process_user_notification_schedules.rb DEV: Enable Style/RedundantBegin rubocop rule (#40096) 2026-05-19 18:44:54 +02:00
purge_deleted_uploads.rb
purge_expired_ignored_users.rb
purge_old_mini_scheduler_stat.rb DEV: Split weekly job into multiple smaller jobs (#31260) 2025-02-11 10:26:45 +02:00
purge_old_notifications.rb DEV: Split weekly job into multiple smaller jobs (#31260) 2025-02-11 10:26:45 +02:00
purge_old_web_hook_events.rb
purge_old_web_hook_events_daily_aggregate.rb FEATURE: Add WebHookEventsDailyAggregate (#27542) 2024-06-25 13:56:47 -03:00
purge_unactivated.rb
redeliver_web_hook_events.rb FIX: Match webhook-related messagebus audience to controller audience (#40693) 2026-06-09 18:22:26 +01:00
regenerate_sitemaps.rb
reindex_search.rb DEV: Move private method to bottom of file 2026-02-09 18:41:22 +00:00
reviewable_priorities.rb
run_problem_checks.rb FIX: Problem checks running with NO_TARGET (#37430) 2026-02-02 15:28:58 +10:00
schedule_backup.rb DEV: Rename Backuper to Creator 2026-01-22 18:46:02 +00:00
tl3_promotions.rb DEV: Add tl3_custom_promotions plugin modifier to tl3_promotions.rb (#29834) 2024-11-22 15:28:43 -05:00
top_refresh_older.rb
top_refresh_today.rb
topic_timer_enqueuer.rb DEV: Enable Style/RedundantBegin rubocop rule (#40096) 2026-05-19 18:44:54 +02:00
unsilence_users.rb
update_animated_uploads.rb DEV: Remove logical OR assignment of constants (#29201) 2024-10-16 10:09:07 +08:00
update_heat_settings.rb
update_topic_hot_scores.rb DEV: Update rubocop-discourse to 3.13 and autofix issues (#35073) 2025-10-06 16:11:01 +02:00