-
Notifications
You must be signed in to change notification settings - Fork 8
fix: standardize API token format across all creation paths #44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
d66f9c8
68474fc
446b7c4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,9 @@ | |
| from backend.utils.tenant_context import get_current_tenant | ||
|
|
||
| from backend.core.models.api_tokens import APIToken | ||
| from backend.core.services.api_key_audit import log_api_key_event | ||
| from backend.core.services.api_key_service import generate_api_key, generate_signature | ||
| from django.conf import settings as django_settings | ||
| from django.utils.timezone import now | ||
| from datetime import timedelta | ||
|
|
||
|
|
@@ -52,16 +55,29 @@ def update_user_profile(request: Request) -> Response: | |
|
|
||
|
|
||
| def update_user_token(request, user): | ||
| new_token = request.data.get("token") | ||
| existing_token: APIToken = APIToken.objects.filter(user=user).first() | ||
| # token_value is sent back by the frontend — used only to detect "unchanged" | ||
| token_value = request.data.get("token") | ||
| existing_token: APIToken = APIToken.objects.filter(user=user, label="Default").first() | ||
|
|
||
| if new_token: | ||
| if existing_token and existing_token.token == new_token: | ||
| if token_value: | ||
| # Skip regeneration if the token hasn't changed | ||
| if existing_token and existing_token.token == token_value: | ||
| return | ||
| if existing_token: | ||
| existing_token.delete() | ||
|
|
||
| APIToken.objects.create(user=user, token=new_token, expires_at= now() + timedelta(days=90)) | ||
| api_key = generate_api_key() | ||
| token = APIToken.objects.create( | ||
| user=user, | ||
| token=api_key, | ||
| signature=generate_signature(api_key), | ||
| label="Default", | ||
| expires_at=now() + timedelta(days=django_settings.API_KEY_EXPIRY_DAYS), | ||
| ) | ||
greptile-apps[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| log_api_key_event( | ||
| request, action="create", key_id=token.id, | ||
| key_label="Default", key_masked=token.masked_token, | ||
| ) | ||
|
Comment on lines
+62
to
+80
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Before this PR Consider adding the same count check: max_keys = django_settings.MAX_KEYS_PER_USER
if APIToken.objects.filter(user=user).count() >= max_keys:
return # or surface an appropriate errorPrompt To Fix With AIThis is a comment left during a code review.
Path: backend/backend/core/views.py
Line: 62-80
Comment:
**`MAX_KEYS_PER_USER` limit not enforced in `update_user_token`**
Before this PR `update_user_token` stored the raw frontend string — no real DB row was inserted. Now it calls `APIToken.objects.create(...)` (line 70), creating a real row that counts against the per-user key cap. However, no `MAX_KEYS_PER_USER` guard is applied before the create call, unlike `create_api_key`. A user who has reached the maximum via the KeyManagement UI can get an extra token simply by saving their profile page.
Consider adding the same count check:
```python
max_keys = django_settings.MAX_KEYS_PER_USER
if APIToken.objects.filter(user=user).count() >= max_keys:
return # or surface an appropriate error
```
How can I resolve this? If you propose a fix, please make it concise.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Acknowledged — low risk in practice since both paths only create |
||
| else: | ||
| if existing_token: | ||
| existing_token.delete() | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MAX_KEYS_PER_USERlimit not enforced on new-token creation pathThe upsert logic correctly updates an existing
"Default"token in-place, but when no"Default"token exists theelsebranch creates a brand-newAPITokenrecord without first checkingMAX_KEYS_PER_USER. A user who already holds the maximum number of non-Default keys can call this legacy endpoint to silently create an extra token that exceeds the per-user cap enforced bycreate_api_key.create_api_key(lines 66–72 of the same file) shows the guard pattern:The same check should be added to
generate_tokenbefore theelsebranch creates a new record.Prompt To Fix With AI