Add Basic Auth Support#1089
Conversation
Adds username/password authentication mode for self-hosted instances that want to manage users manually without OAuth providers.
Changes:
Backend:
- basic_auth.py: Login endpoint and metadata endpoint returning {"google": null}
- state.py: Added controlled_access_mode flag
- main.py: CLI flag and env var handling
- configure.py: Router mounting and auth middleware
Frontend (loginPrompt.tsx):
- Basic auth detection from metadata response
- Username/password form with loading/error states
- Works in both mobile/desktop views
- Preserves existing OAuth/email flows
Usage:
1. Enable controlled access mode via:
- CLI: --controlled-access
- ENV: KHOJ_CONTROLLED_ACCESS=true
2. Initial admin credentials:
- Username: admin@example.com
- Password: admin
3. Managing Users:
- Login as admin at http://localhost:42110/server/admin
- Use Django admin interface to:
* Create new users
* Set passwords
* Manage permissions
- Users can then login with their credentials at http://localhost:42110
Security Notes:
- Default admin should be changed after first login
- Each user needs to be manually created by admin
- No self-registration - controlled environment
Testing:
```bash
docker compose up # Uses KHOJ_CONTROLLED_ACCESS=true
```
1. Visit http://localhost:42110 - should show username/password form
2. Login with admin credentials
3. Create test user in admin panel
4. Test login with new user
| # build: | ||
| # context: . | ||
| build: | ||
| context: . | ||
| dockerfile: Dockerfile |
There was a problem hiding this comment.
Given context: . defaults to dockerfile: Dockerfile, the new dockerfile: Dockerfile line shouldn't be necessary
| build: | ||
| context: . | ||
| dockerfile: Dockerfile |
There was a problem hiding this comment.
This should be commented out by default and the image: config above should be uncommented, so folks can use the pre-built image (instead of having to build the docker image locally)
| command: --host="0.0.0.0" --port=42110 -vv --anonymous-mode --non-interactive | ||
| entrypoint: python3 src/khoj/main.py --host=0.0.0.0 --port=42110 -vv --controlled-access --non-interactive | ||
| # entrypoint: python3 src/khoj/main.py --host=0.0.0.0 --port=42110 -vv --anonymous-mode --non-interactive | ||
| # entrypoint: python3 src/khoj/main.py --host=0.0.0.0 --port=42110 -vv --non-interactive |
There was a problem hiding this comment.
Enabling basic auth via environment variable maybe better. That is by adding - ENABLE_CONTROLLED_ACCESS=True in the environment section for the Khoj service above
| # - KHOJ_TELEMETRY_DISABLE=True | ||
| # Comment out this line when you're using the official ghcr.io/khoj-ai/khoj-cloud:latest prod image. | ||
| command: --host="0.0.0.0" --port=42110 -vv --anonymous-mode --non-interactive | ||
| entrypoint: python3 src/khoj/main.py --host=0.0.0.0 --port=42110 -vv --controlled-access --non-interactive |
There was a problem hiding this comment.
We can revert this be a command as the Dockerfile sets the ENTRYPOINT to python3 src/khoj/main.py already
| # - KHOJ_TELEMETRY_DISABLE=True | ||
| # Comment out this line when you're using the official ghcr.io/khoj-ai/khoj-cloud:latest prod image. | ||
| command: --host="0.0.0.0" --port=42110 -vv --anonymous-mode --non-interactive | ||
| entrypoint: python3 src/khoj/main.py --host=0.0.0.0 --port=42110 -vv --controlled-access --non-interactive |
There was a problem hiding this comment.
We should default to anonymous mode for self-hosting users in my opinion. Multi-user setups for self-hosting users is not expected to be default
| # Add auth router if not in anonymous mode | ||
| if not state.anonymous_mode: | ||
| from khoj.routers.auth import auth_router | ||
| if state.controlled_access_mode: |
There was a problem hiding this comment.
Same ordering of conditionals comment as above. Let's check for OAuth first (i.e if not state.controlled_access_mode <add_oauth_router> else: <add_basic_auth_router>)
| # Handle WhatsApp client | ||
| client_id = request.query_params.get("client_id") | ||
| if client_id: | ||
| # Get the client secret, which is passed in the Authorization header |
There was a problem hiding this comment.
Should we keep this and the comment below?
| @@ -4,38 +4,38 @@ | |||
|
|
|||
| "@alloc/quick-lru@^5.2.0": | |||
| version "5.2.0" | |||
| resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" | |||
| resolved "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz" | |||
There was a problem hiding this comment.
This should be reverted to use yarn instead of npm, e.g yarn install
| django==5.0.10 \ | ||
| fastapi==0.115.6 \ | ||
| uvicorn==0.30.6 \ | ||
| pydantic==2.10.5 \ | ||
| starlette==0.41.3 |
There was a problem hiding this comment.
Unclear why django and other package dependencies are being installed here instead of in pyproject.toml which also installs these dependencies
There was a problem hiding this comment.
We should revert changes to this file, they seem tangential to this PR
535f353 to
0f0cfba
Compare
|
Closing this PR for now. It has gone stale and comments haven't been resolved. |
Adds username/password authentication mode for self-hosted instances that want to manage users manually without OAuth providers.
Changes:
Backend:
Frontend (loginPrompt.tsx):
Usage:
Enable controlled access mode via:
Initial admin credentials:
Managing Users:
Security Notes:
Testing:
docker compose up # Uses KHOJ_CONTROLLED_ACCESS=true