Skip to content

feat(api_keys): implement API key management with CRUD operations and permissions#549

Open
ImMohammad20000 wants to merge 21 commits into
devfrom
apikey
Open

feat(api_keys): implement API key management with CRUD operations and permissions#549
ImMohammad20000 wants to merge 21 commits into
devfrom
apikey

Conversation

@ImMohammad20000
Copy link
Copy Markdown
Contributor

@ImMohammad20000 ImMohammad20000 commented May 31, 2026

Summary by CodeRabbit

Release Notes

  • New Features

    • API key management system enabling creation, listing, retrieval, and deletion of API keys
    • API key authentication as an alternative to bearer token authentication
    • Role-based permission controls for API key operations per admin role
    • API key expiration support with automatic validation
  • Chores

    • Removed unused import in user operation module

Comment thread app/utils/crypto.py Fixed
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a6ae4430-e732-407b-8c01-d2075e2f018a

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
  • Commit unit tests in branch apikey

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.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 2026

Note

Unit test generation is a public access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@ImMohammad20000
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot added enhancement New feature or request Backend labels May 31, 2026
Copy link
Copy Markdown

@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: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/db/crud/api_key.py`:
- Around line 17-24: The APIKey is being created with key_hash computed from
model.raw_key which doesn't exist; change the code to hash the generated raw_key
variable instead (use hash_api_key(raw_key) when constructing the APIKey object
in the APIKey creation flow), ensure the local raw_key (the str(uuid.uuid4())
you create) is used for key_hash in the APIKey constructor (and return or expose
raw_key to the caller if the plain token must be delivered).

In `@app/operation/admin.py`:
- Around line 125-129: The admin update and API key role sync must be atomic:
move the call to update_api_keys_role(db, db_admin.id, modified_admin.role_id)
so it executes inside the same transaction managed by update_admin (i.e., before
the commit that persists the admin change), or ensure update_admin wraps both
operations in one transaction and only commits after update_api_keys_role
succeeds; update any commits so there is a single commit after both operations
and remove the separate commit() call currently after update_api_keys_role to
avoid partial persistence.

In `@app/routers/api_key.py`:
- Line 36: The delete handler remove_api_key currently sets
status_code=status.HTTP_204_NO_CONTENT but returns an empty dict which produces
a response body; change remove_api_key to return nothing or explicitly return
starlette.responses.Response(status_code=status.HTTP_204_NO_CONTENT) and import
Response, ensuring no response body is sent. Also confirm the collection route
decorator `@router.get`("s", response_model=APIKeysResponse) is intentionally
using the "s" suffix (it matches the repo convention) and requires no change.

In `@app/routers/authentication.py`:
- Around line 204-213: The current get_current function only falls back to
X-Api-Key when token is absent, so a present-but-invalid/expired bearer token
prevents the API-key path; change get_current (and the other get_current*
variant around 229-241) to: if token is present, call await get_admin(db, token)
but if that call returns falsy OR raises the usual auth exceptions, then extract
api_key via _extract_api_key(request) and call await get_admin_from_api_key(db,
api_key); i.e., treat a failed/exceptional get_admin result as a trigger to
attempt the API-key fallback. Ensure you reference the same helpers: get_admin,
get_admin_from_api_key, and _extract_api_key.

In `@app/utils/crypto.py`:
- Around line 104-115: hash_api_key currently generates a new random salt every
call (in hash_api_key), so identical API keys yield different stored strings and
cannot be matched via exact DB lookup; instead, change the flow so hash_api_key
returns a stable lookup identifier plus the salted PBKDF2 hash for verification
(e.g., generate a key_id/prefix deterministically from the raw key using a
server-side HMAC or a stable fingerprint and store that as the DB lookup column,
while keeping the salted pbkdf2 output for verification), and implement/ensure a
separate verify_api_key(raw_api_key, stored_hash) that pbkdf2-verifies using the
salt embedded in stored_hash; update any code that does exact equality checks to
query by the deterministic key_id/prefix rather than the full salted hash.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ba79ec72-74bb-42b5-a06f-e2770d0a9ece

📥 Commits

Reviewing files that changed from the base of the PR and between 5656e5e and efc3b8a.

📒 Files selected for processing (15)
  • app/db/crud/api_key.py
  • app/db/migrations/versions/c9b48df42f10_add_api_keys_table.py
  • app/db/models.py
  • app/models/admin_role.py
  • app/models/api_key.py
  • app/operation/admin.py
  • app/operation/api_key.py
  • app/operation/user.py
  • app/routers/__init__.py
  • app/routers/api_key.py
  • app/routers/authentication.py
  • app/routers/dependencies/__init__.py
  • app/routers/dependencies/api_key.py
  • app/utils/crypto.py
  • tests/api/test_user.py

Comment thread app/db/crud/api_key.py
Comment on lines +108 to +114
rows = conn.execute(sa.select(admin_roles.c.id, admin_roles.c.permissions)).fetchall()
for role_id, role_permissions in rows:
permissions = _normalize_permissions(role_permissions)
if "api_keys" not in permissions:
continue
permissions.pop("api_keys", None)
conn.execute(admin_roles.update().where(admin_roles.c.id == role_id).values(permissions=permissions))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Preserve pre-existing api_keys permissions on downgrade.

upgrade() explicitly skips roles that already have an "api_keys" entry, but downgrade() removes that entry from every role unconditionally. Rolling this migration back will therefore delete pre-existing custom permission data, not just the defaults introduced here. Please make the downgrade remove only the values added by this migration, or otherwise preserve original role data.

Comment thread app/operation/admin.py Outdated
Comment thread app/routers/api_key.py
Comment thread app/routers/authentication.py Outdated
Comment thread app/utils/crypto.py Outdated
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 2026

✅ Created PR with unit tests: #551

Comment thread app/utils/crypto.py
Comment thread app/utils/crypto.py Dismissed
Comment thread app/utils/crypto.py Dismissed
@ImMohammad20000 ImMohammad20000 marked this pull request as ready for review May 31, 2026 13:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Backend enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants