Skip to content

fix: require auth for user creation when AUTO_LOGIN is disabled#12385

Open
xr843 wants to merge 3 commits intolangflow-ai:mainfrom
xr843:fix/restrict-user-creation-auto-login-false
Open

fix: require auth for user creation when AUTO_LOGIN is disabled#12385
xr843 wants to merge 3 commits intolangflow-ai:mainfrom
xr843:fix/restrict-user-creation-auto-login-false

Conversation

@xr843
Copy link
Copy Markdown

@xr843 xr843 commented Mar 29, 2026

Summary

  • Fixes a security issue where POST /api/v1/user allowed unrestricted user creation when LANGFLOW_AUTO_LOGIN=False, enabling database flooding with inactive users
  • Adds a check_user_creation_permission dependency that requires superuser authentication when AUTO_LOGIN is disabled (production mode)
  • Preserves the existing public registration behavior when AUTO_LOGIN=True (development mode)

Closes #12278

Implementation

Uses the existing get_optional_user dependency (which returns None for unauthenticated requests instead of raising) to conditionally enforce superuser auth based on the AUTO_LOGIN setting. This keeps the change minimal — only one file modified, no new settings or environment variables needed.

Test plan

  • Verify with AUTO_LOGIN=True: unauthenticated POST /api/v1/user still works (public registration)
  • Verify with AUTO_LOGIN=False: unauthenticated POST /api/v1/user returns 403
  • Verify with AUTO_LOGIN=False: authenticated superuser POST /api/v1/user succeeds
  • Verify with AUTO_LOGIN=False: authenticated non-superuser POST /api/v1/user returns 403
  • Verify existing user endpoints (GET, PATCH, DELETE) are unaffected

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • User registration is now restricted when AUTO_LOGIN is disabled—only superusers can create new accounts in this mode.
  • Chores

    • Updated internal dependency versions.

…bled

When LANGFLOW_AUTO_LOGIN=False (production mode), the POST /api/v1/user
endpoint was completely unprotected, allowing anyone to create users
without authentication. While these users were created as inactive, this
still allowed malicious actors to flood the database with inactive users.

This adds a permission check that requires superuser authentication for
user creation when AUTO_LOGIN is disabled, using the existing
get_optional_user dependency to avoid breaking the AUTO_LOGIN=True
(development mode) flow where public registration is expected.

Closes langflow-ai#12278

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@github-actions github-actions bot added the community Pull Request from an external contributor label Mar 29, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 29, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

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: 36e3b404-c0ca-4dfa-8018-1b741840a913

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

Walkthrough

A new permission-checking dependency was added to the user creation endpoint that restricts registration when AUTO_LOGIN is disabled, requiring the caller to be an authenticated, active superuser. Additionally, Google dependency versions were updated in the component index configuration file.

Changes

Cohort / File(s) Summary
User Creation Access Control
src/backend/base/langflow/api/v1/users.py
Added check_user_creation_permission dependency that enforces superuser-only registration when AUTO_LOGIN is False. Updated add_user endpoint to use this dependency. Extended imports to include get_optional_user.
Component Index Configuration
src/lfx/src/lfx/_assets/component_index.json
Updated Google dependency version from 2.30.0 to 2.8.0 across multiple component entries and updated corresponding sha256 checksum.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Test Coverage For New Implementations ❌ Error PR introduces critical authentication mechanism for user creation without comprehensive test coverage for all four specified scenarios. Add test cases covering: (1) public registration with AUTO_LOGIN=True, (2) 403 for unauthenticated requests with AUTO_LOGIN=False, (3) superuser success, (4) non-superuser rejection. Fix failing tests and address code style violations.
Test Quality And Coverage ⚠️ Warning Test suite lacks coverage for new security feature with broken existing tests and missing PR objective scenarios. Add tests for all four PR scenarios and fix broken tests by setting AUTO_LOGIN=True or providing superuser auth.
Out of Scope Changes check ❓ Inconclusive The component_index.json changes appear unrelated to the security fix for user creation protection, but may represent necessary dependency updates; the user creation restriction implementation itself is properly scoped. Clarify the purpose of the google dependency version downgrade (2.30.0 to 2.8.0) in component_index.json to confirm it's not an unintended change or merge artifact unrelated to user authentication.
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main security fix: requiring authentication for user creation when AUTO_LOGIN is disabled, which directly addresses the PR's primary objective.
Linked Issues check ✅ Passed The PR implementation successfully addresses all coding requirements from issue #12278: restricting user creation when AUTO_LOGIN=False [#12278], preserving public registration when AUTO_LOGIN=True [#12278], and protecting the POST /api/v1/user endpoint [#12278].
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Test File Naming And Structure ✅ Passed Test files follow all specified patterns: proper naming convention (test_*.py), descriptive test function names, comprehensive implementations with proper pytest fixtures, AsyncClient usage, and coverage of positive/negative scenarios and edge cases.
Excessive Mock Usage Warning ✅ Passed Tests use real dependencies via fixtures without explicit mocking (no mock/Mock/patch calls found), validating actual behavior rather than obscuring it.
✨ 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 the bug Something isn't working label Mar 29, 2026
@github-actions github-actions bot added bug Something isn't working and removed bug Something isn't working labels Mar 29, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/backend/base/langflow/api/v1/users.py`:
- Around line 31-36: Combine the nested condition into a single if to satisfy
ruff SIM102: replace the two-level check with one statement like "if not
settings_service.auth_settings.AUTO_LOGIN and (current_user is None or not
current_user.is_active or not current_user.is_superuser): raise
HTTPException(...)" so the raise remains the same and references
settings_service.auth_settings.AUTO_LOGIN, current_user, current_user.is_active,
current_user.is_superuser, and HTTPException.
- Line 43: The dependency parameter currently uses the old pattern "_: None =
Depends(check_user_creation_permission)" which triggers Ruff FAST002; update the
function signature to use typing.Annotated for FastAPI DI by replacing that
parameter with Annotated[None, Depends(check_user_creation_permission)] and
add/ensure "from typing import Annotated" is imported; locate the parameter
where check_user_creation_permission is referenced in
src/backend/base/langflow/api/v1/users.py and apply the change.
- Around line 21-36: The test test_add_user_public_signup fails because
check_user_creation_permission blocks unauthenticated creation when
settings_service.auth_settings.AUTO_LOGIN is false; fix the test by either
setting AUTO_LOGIN=True for that test (override LANGFLOW_AUTO_LOGIN in the test
fixture or settings mock) or call the endpoint with superuser credentials using
the existing logged_in_headers_super_user fixture as other tests do (refer to
check_user_creation_permission, AUTO_LOGIN, test_add_user_public_signup and
logged_in_headers_super_user to locate the relevant code).

In `@src/lfx/src/lfx/_assets/component_index.json`:
- Line 73434: The component_index.json changes (entries like the "version":
"2.8.0" lines in src/lfx/src/lfx/_assets/component_index.json and the other
listed offsets) look unrelated to the AUTO_LOGIN/authentication fix—please
confirm intent: if they are accidental, revert those version changes from the
commit (undo edits to component_index.json) so the PR only contains the auth
fix; if they are intentional, add a short note in the PR description explaining
why these dependency/version downgrades are required for the
user-creation/authentication changes and split them into a separate dependency
update PR (or create a separate commit clearly titled for dependency updates).
Ensure references to component_index.json and the specific "version" entries are
addressed when reverting or separating.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 65419cdd-2f26-4201-9346-4a07275ad291

📥 Commits

Reviewing files that changed from the base of the PR and between 08bf984 and bb90c97.

📒 Files selected for processing (2)
  • src/backend/base/langflow/api/v1/users.py
  • src/lfx/src/lfx/_assets/component_index.json

Comment on lines +21 to +36
async def check_user_creation_permission(
current_user: Annotated[User | None, Depends(get_optional_user)],
) -> None:
"""Restrict user creation to superusers when AUTO_LOGIN is disabled.

When AUTO_LOGIN is True (development mode), anyone can register.
When AUTO_LOGIN is False (production mode), only authenticated superusers
can create new users to prevent unrestricted user creation.
"""
settings_service = get_settings_service()
if not settings_service.auth_settings.AUTO_LOGIN:
if current_user is None or not current_user.is_active or not current_user.is_superuser:
raise HTTPException(
status_code=403,
detail="User registration is disabled. Only superusers can create new users.",
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check how test_n_public_signup handles AUTH_LOGIN setting
rg -nA 20 'test_n_public_signup' --type=py

Repository: langflow-ai/langflow

Length of output: 46


🏁 Script executed:

# Search for signup/registration related tests
rg -i 'signup|registration' --type=py src/backend/tests/ | head -30

Repository: langflow-ai/langflow

Length of output: 3796


🏁 Script executed:

# Search for test files related to users or auth
fd -t f 'test.*user.*\.py|test.*auth.*\.py' src/backend/tests/

Repository: langflow-ai/langflow

Length of output: 579


🏁 Script executed:

# Search for any test that creates users
rg -n 'def test.*user.*create|def test.*sign' --type=py src/backend/tests/

Repository: langflow-ai/langflow

Length of output: 4411


🏁 Script executed:

# Check conftest.py for AUTO_LOGIN setting
rg -n 'AUTO_LOGIN|LANGFLOW_AUTO_LOGIN' --type=py src/backend/tests/

Repository: langflow-ai/langflow

Length of output: 8409


🏁 Script executed:

cat -n src/backend/tests/unit/api/v1/test_users.py

Repository: langflow-ai/langflow

Length of output: 10562


🏁 Script executed:

rg -n 'def.*add_user|@.*\.post.*users' -A 10 src/backend/base/langflow/api/v1/users.py | head -50

Repository: langflow-ai/langflow

Length of output: 487


🏁 Script executed:

# Check the complete context of the user creation endpoint
cat -n src/backend/base/langflow/api/v1/users.py | head -100

Repository: langflow-ai/langflow

Length of output: 4523


🏁 Script executed:

# Check the client fixture in conftest to see if it configures AUTO_LOGIN differently
rg -B 5 -A 20 'def client' src/backend/tests/conftest.py | head -80

Repository: langflow-ai/langflow

Length of output: 903


🏁 Script executed:

# Check if there are any monkeypatch setups specific to test_add_user_public_signup
rg -B 10 'test_add_user_public_signup' src/backend/tests/unit/api/v1/test_users.py

Repository: langflow-ai/langflow

Length of output: 182


Fix test test_add_user_public_signup to set AUTO_LOGIN=True or add superuser authentication.

The test at src/backend/tests/unit/api/v1/test_users.py:5-22 calls POST without authentication and expects HTTP 201, but the endpoint's check_user_creation_permission dependency will reject it with HTTP 403 because:

  • The client fixture in conftest.py:296 sets LANGFLOW_AUTO_LOGIN=false by default
  • The test does not override this setting or provide superuser credentials

Either set AUTO_LOGIN=True within the test or provide logged_in_headers_super_user (as done in other tests like test_add_user at line 38).

🧰 Tools
🪛 GitHub Actions: Ruff Style Check

[error] 31-31: ruff check failed (SIM102): Use a single if statement instead of nested if statements.

🪛 GitHub Check: Ruff Style Check (3.13)

[failure] 31-32: Ruff (SIM102)
src/backend/base/langflow/api/v1/users.py:31:5: SIM102 Use a single if statement instead of nested if statements

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/api/v1/users.py` around lines 21 - 36, The test
test_add_user_public_signup fails because check_user_creation_permission blocks
unauthenticated creation when settings_service.auth_settings.AUTO_LOGIN is
false; fix the test by either setting AUTO_LOGIN=True for that test (override
LANGFLOW_AUTO_LOGIN in the test fixture or settings mock) or call the endpoint
with superuser credentials using the existing logged_in_headers_super_user
fixture as other tests do (refer to check_user_creation_permission, AUTO_LOGIN,
test_add_user_public_signup and logged_in_headers_super_user to locate the
relevant code).

Comment on lines +31 to +36
if not settings_service.auth_settings.AUTO_LOGIN:
if current_user is None or not current_user.is_active or not current_user.is_superuser:
raise HTTPException(
status_code=403,
detail="User registration is disabled. Only superusers can create new users.",
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix nested if statements to resolve pipeline failure.

The ruff linter (SIM102) requires combining nested if statements into a single statement. This is causing the pipeline to fail.

🔧 Proposed fix
     settings_service = get_settings_service()
-    if not settings_service.auth_settings.AUTO_LOGIN:
-        if current_user is None or not current_user.is_active or not current_user.is_superuser:
-            raise HTTPException(
-                status_code=403,
-                detail="User registration is disabled. Only superusers can create new users.",
-            )
+    if (
+        not settings_service.auth_settings.AUTO_LOGIN
+        and (current_user is None or not current_user.is_active or not current_user.is_superuser)
+    ):
+        raise HTTPException(
+            status_code=403,
+            detail="User registration is disabled. Only superusers can create new users.",
+        )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if not settings_service.auth_settings.AUTO_LOGIN:
if current_user is None or not current_user.is_active or not current_user.is_superuser:
raise HTTPException(
status_code=403,
detail="User registration is disabled. Only superusers can create new users.",
)
if (
not settings_service.auth_settings.AUTO_LOGIN
and (current_user is None or not current_user.is_active or not current_user.is_superuser)
):
raise HTTPException(
status_code=403,
detail="User registration is disabled. Only superusers can create new users.",
)
🧰 Tools
🪛 GitHub Actions: Ruff Style Check

[error] 31-31: ruff check failed (SIM102): Use a single if statement instead of nested if statements.

🪛 GitHub Check: Ruff Style Check (3.13)

[failure] 31-32: Ruff (SIM102)
src/backend/base/langflow/api/v1/users.py:31:5: SIM102 Use a single if statement instead of nested if statements

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/api/v1/users.py` around lines 31 - 36, Combine the
nested condition into a single if to satisfy ruff SIM102: replace the two-level
check with one statement like "if not settings_service.auth_settings.AUTO_LOGIN
and (current_user is None or not current_user.is_active or not
current_user.is_superuser): raise HTTPException(...)" so the raise remains the
same and references settings_service.auth_settings.AUTO_LOGIN, current_user,
current_user.is_active, current_user.is_superuser, and HTTPException.

async def add_user(
user: UserCreate,
session: DbSession,
_: None = Depends(check_user_creation_permission),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use Annotated for FastAPI dependency injection.

Ruff FAST002 requires using Annotated for FastAPI dependencies. This is the modern pattern and aligns with other dependencies in this file.

🔧 Proposed fix
 async def add_user(
     user: UserCreate,
     session: DbSession,
-    _: None = Depends(check_user_creation_permission),
+    _: Annotated[None, Depends(check_user_creation_permission)],
 ) -> User:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
_: None = Depends(check_user_creation_permission),
_: Annotated[None, Depends(check_user_creation_permission)],
🧰 Tools
🪛 GitHub Check: Ruff Style Check (3.13)

[failure] 43-43: Ruff (FAST002)
src/backend/base/langflow/api/v1/users.py:43:5: FAST002 FastAPI dependency without Annotated

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/api/v1/users.py` at line 43, The dependency
parameter currently uses the old pattern "_: None =
Depends(check_user_creation_permission)" which triggers Ruff FAST002; update the
function signature to use typing.Annotated for FastAPI DI by replacing that
parameter with Annotated[None, Depends(check_user_creation_permission)] and
add/ensure "from typing import Annotated" is imported; locate the parameter
where check_user_creation_permission is referenced in
src/backend/base/langflow/api/v1/users.py and apply the change.

{
"name": "google",
"version": "2.30.0"
"version": "2.8.0"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Verify that component index changes are intentionally included in this PR.

The changes to component_index.json (Google dependency version downgrades) appear unrelated to the stated PR objectives, which focus on fixing authentication for user creation when AUTO_LOGIN is disabled.

This could indicate:

  • Accidental inclusion from a different branch or merge
  • Intentional bundling of unrelated changes (generally discouraged)
  • A dependency update required for the authentication fix (unclear why)

Please confirm whether these changes should be part of this PR or separated into a different PR focused on dependency updates.

Also applies to: 73582-73582, 73743-73743, 73872-73872, 74001-74001, 74291-74291, 74651-74651, 113848-113848, 114232-114232, 118490-118490

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lfx/src/lfx/_assets/component_index.json` at line 73434, The
component_index.json changes (entries like the "version": "2.8.0" lines in
src/lfx/src/lfx/_assets/component_index.json and the other listed offsets) look
unrelated to the AUTO_LOGIN/authentication fix—please confirm intent: if they
are accidental, revert those version changes from the commit (undo edits to
component_index.json) so the PR only contains the auth fix; if they are
intentional, add a short note in the PR description explaining why these
dependency/version downgrades are required for the user-creation/authentication
changes and split them into a separate dependency update PR (or create a
separate commit clearly titled for dependency updates). Ensure references to
component_index.json and the specific "version" entries are addressed when
reverting or separating.

@github-actions github-actions bot added bug Something isn't working and removed bug Something isn't working labels Mar 30, 2026
@xr843
Copy link
Copy Markdown
Author

xr843 commented Mar 30, 2026

Hi maintainers, the Ruff Style Check failure is not related to this PR.

The error is a pre-existing PERF403 violation in src/backend/base/langflow/initial_setup/setup.py:68, which is not a file modified by this PR. The same violation exists on the main branch.

Happy to rebase once this is resolved upstream!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working community Pull Request from an external contributor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Users API: it should be possible to block unrestricted user creation if LANGFLOW_AUTO_LOGIN is false

1 participant