Skip to content

feat(security): implement TOTP two-factor authentication support#12615

Open
severfire wants to merge 1 commit into
langflow-ai:release-1.10.0from
severfire:feat-TOTP-auth
Open

feat(security): implement TOTP two-factor authentication support#12615
severfire wants to merge 1 commit into
langflow-ai:release-1.10.0from
severfire:feat-TOTP-auth

Conversation

@severfire
Copy link
Copy Markdown
Contributor

@severfire severfire commented Apr 10, 2026

feat: TOTP Two-Factor Authentication

Summary

This PR adds opt-in TOTP (Time-based One-Time Password) two-factor authentication to Langflow, compatible with Google Authenticator, Authy, and any RFC 6238-compliant app. Users can enable 2FA from the Settings page; once enabled, login requires both the password and a 6-digit code from their authenticator app.


What Changed

Backend

New service — services/auth/totp.py

  • RFC 6238 TOTP implementation via pyotp
  • TOTP secrets are Fernet-encrypted at rest (using the existing application SECRET_KEY) before being written to the database
  • Replay attack prevention: each verified code is placed in a process-local TTLCache for 3 TOTP windows (90 s); re-using the same code within that window is rejected
  • Partial-token brute-force protection: a short-lived (5-min) partial_token is issued at password-login when the user has TOTP enabled; after MAX_VERIFY_ATTEMPTS (5) consecutive wrong codes, the token is permanently burned
  • ±30 s clock-drift tolerance (valid_window=1)

New router — api/v1/totp.py

Method Path Description
GET /api/v1/totp/status Check if TOTP is enabled for the current user
POST /api/v1/totp/setup Generate a new TOTP secret + QR provisioning URI (does not persist yet)
POST /api/v1/totp/enable Verify the first code and persist the encrypted secret
POST /api/v1/totp/disable Verify the current code then wipe the stored secret
POST /api/v1/totp/verify-login Complete a partial-token login by verifying the 6-digit code

Modified — api/v1/login.py

  • When a user with TOTP enabled logs in with valid credentials, the response now returns a short-lived partial_token instead of full access/refresh tokens
  • Full tokens are only issued after successful TOTP verification via /totp/verify-login

Database migration — alembic/versions/a3b4c5d6e7f8_add_totp_fields_to_user.py

  • Adds totp_secret (VARCHAR, nullable) and totp_enabled (BOOLEAN, default false) columns to the user table

Dependencypyotp added to langflow-base dependencies

Frontend

New component — SettingsPage/GeneralPage/components/TotpForm

  • Card-based UI with three views: statussetupdisable
  • Setup view: displays a scannable QR code (via qrcode.react) alongside the raw base32 secret for manual entry, then asks the user to enter the first 6-digit code to confirm enrollment
  • Disable view: asks for a live 6-digit code before removing 2FA
  • autoComplete="one-time-code" on all OTP inputs for browser/OS autofill support

New React Query hooks — controllers/API/queries/auth/

  • useGetTotpStatus — query for current TOTP status
  • usePostTotpSetup — mutation to generate a new secret
  • usePostTotpEnable — mutation to confirm and enable
  • usePostTotpDisable — mutation to disable with code verification
  • usePostTotpVerifyLogin — mutation to complete the 2FA login step

Modified — pages/LoginPage/index.tsx

  • After a successful password login the server may return a partial_token; when it does, the login form transitions to a TOTP code-entry step
  • Full login is completed only when the verify-login API call succeeds

i18n — locales/en.json

  • Added 17 new translation keys covering TOTP titles, descriptions, buttons, and error messages

Dependencyqrcode.react added to package.json

Tests

src/backend/tests/unit/test_totp.py (557 lines)

  • Unit tests for the TOTP utility layer (secret generation, encryption/decryption, replay prevention, partial-token lifecycle)
  • Integration-style tests for all five API endpoints, covering success paths, invalid codes, replay attempts, expired/burned partial tokens, and brute-force lockout

Security Design Notes

  • The TOTP secret is never stored in plaintext; Fernet encryption is applied before any database write
  • The partial_token is JWT-signed with type: "partial", preventing it from being used as a normal session token
  • Each partial token is single-use: a successful TOTP verification burns it immediately
  • After 5 failed attempts the partial token is also burned, requiring the user to re-enter their password — this prevents offline enumeration of the 6-digit code space
  • Per-code replay prevention uses the same cache across the ±1-window drift range, so a code that straddles a window boundary cannot be submitted twice

Test Plan

  • Register / log in as a user without TOTP enabled — confirm normal login flow is unchanged
  • Navigate to Settings → General, enable TOTP: scan QR code with an authenticator app, confirm with the first code
  • Log out and log back in — confirm the 2FA code prompt appears after password entry
  • Enter a wrong code — confirm error; enter correct code — confirm full login
  • Disable TOTP from Settings, confirm code is required to disable
  • Run backend unit tests: uv run pytest src/backend/tests/unit/test_totp.py

- Added TOTP (Time-based One-Time Password) functionality for enhanced security.
- Introduced new API endpoints for TOTP setup, enabling, disabling, and verifying login.
- Updated user model to include TOTP secret and enabled status.
- Integrated TOTP checks into the login process, requiring a second factor for users with TOTP enabled.
- Added frontend components and hooks for TOTP management, including status checks and user prompts.
- Updated localization files to include TOTP-related messages and instructions.
- Added unit tests for TOTP functionality and API endpoints.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 10, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: da7066e3-bfd6-46f2-8445-57c9ef672aaa

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Apr 10, 2026
@severfire
Copy link
Copy Markdown
Contributor Author

@ogabrielluiz Hi, could this be released into 1.9.1? :-D I always dreamed about 2FA in Langflow :-)

@jordanrfrazier jordanrfrazier changed the base branch from release-1.9.0 to release-1.10.0 April 21, 2026 12:55
@jordanrfrazier
Copy link
Copy Markdown
Collaborator

@severfire Changed base to v1.10, will get it reviewed for that! Thanks

@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Apr 21, 2026
@severfire
Copy link
Copy Markdown
Contributor Author

@jordanrfrazier Thanks! This PR would be part of the ISO 27001 goals :-)

@severfire severfire changed the title feat: implement TOTP two-factor authentication support feat(security): implement TOTP two-factor authentication support Apr 23, 2026
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Apr 23, 2026
@erichare erichare force-pushed the release-1.10.0 branch 2 times, most recently from 841d2d7 to 242c6c7 Compare April 24, 2026 02:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants