Skip to content

Enabling pat backend clean#336

Open
Ayush4958 wants to merge 4 commits into
geturbackend:mainfrom
Ayush4958:enabling-PAT-backend-clean
Open

Enabling pat backend clean#336
Ayush4958 wants to merge 4 commits into
geturbackend:mainfrom
Ayush4958:enabling-PAT-backend-clean

Conversation

@Ayush4958

@Ayush4958 Ayush4958 commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

🚀 Pull Request Description

I had enabled PAT for project, Now CLI/AI Agents can easily authenticate against Dashboard API.
Added the PAT generator which adds prefix to generated PAT.
Also included PAT schema in developer model.
Added strict PAT validation middleware with Redis caching

🛠️ Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📝 Documentation update
  • 🎨 UI/UX improvement (Frontend only)
  • ⚙️ Refactor / Chore

🧪 Testing & Validation

Backend Verification:

  • I have run npm test in the backend/ directory and all tests passed.
  • I have verified the API endpoints using Postman/Thunder Client.
  • New unit tests have been added (if applicable).

Frontend Verification:

  • I have run npm run lint in the frontend/ directory.
  • Verified the UI changes on different screen sizes (Responsive).
  • Checked for any console errors in the browser dev tools.

✅ Checklist

  • My code follows the code style of this project.
  • I have performed a self-review of my code.
  • I have commented my code, particularly in hard-to-understand areas.
  • My changes generate no new warnings or errors.
  • I have updated the documentation (README/Docs) accordingly.

Summary by CodeRabbit

  • New Features

    • Added personal access token (PAT) management: create, list, and revoke tokens via API
    • PATs support labels, scopes, configurable TTL (1-365 days, default 30 days), and track usage
    • Enabled CLI authentication using personal access tokens
  • Tests

    • Added test mocks for PAT-related functionality

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Ayush4958, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 25 minutes and 59 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ff886d3d-61d1-48ef-b77c-ad1bec15c2eb

📥 Commits

Reviewing files that changed from the base of the PR and between 44dfd21 and 6483ab8.

📒 Files selected for processing (3)
  • apps/dashboard-api/src/controllers/pat.controller.js
  • apps/dashboard-api/src/middlewares/authenticateCLI.js
  • packages/common/src/models/Developer.js
📝 Walkthrough

Walkthrough

This PR introduces a full Personal Access Token (PAT) system. It adds token generation utilities (encodeBase62, generatePAT, hashToken) to the common package, extends the Developer Mongoose model with a patSchema/pats array, implements createPAT, listPATs, and revokePAT controllers, adds a Redis-cached authenticateCLI middleware, wires three new REST endpoints, and stubs controllers in existing tests.

Changes

PAT Feature

Layer / File(s) Summary
Token generation utilities and common exports
packages/common/src/utils/token.utils.js, packages/common/src/index.js
Adds encodeBase62 (BigInt-based Base62 encoder), generatePAT (CSPRNG + ubpat_${env}_ prefix + SHA-256 hash + 4-char suffix), and hashToken (SHA-256 hex digest), all re-exported from the common package index.
Developer model patSchema and pats field
packages/common/src/models/Developer.js
Defines patSchema Mongoose sub-schema (tokenHash, suffix, label, type enum, scopes, lastUsedAt, lastUsedIp, expiresAt, createdAt) and appends pats: [patSchema] defaulting to [] on the Developer model.
PAT CRUD controllers
apps/dashboard-api/src/controllers/pat.controller.js
Implements createPAT (input validation, TTL bounds, env-based token generation, persists to developer.pats, returns raw token once), listPATs (masked metadata array), and revokePAT (removes PAT, deletes Redis key cli:pat:cache:${tokenHash}).
authenticateCLI middleware
apps/dashboard-api/src/middlewares/authenticateCLI.js
Validates Authorization: Bearer ubpat_* header, rejects query-string tokens, resolves developer via Redis-cached tokenHash lookup, checks PAT expiry, asynchronously records lastUsedAt/lastUsedIp, and attaches req.developer, req.cliScopes, req.cliTokenType.
Route wiring and test stubs
apps/dashboard-api/src/routes/user.js, apps/dashboard-api/src/__tests__/routes.user.test.js
Registers POST /pats, GET /pats, DELETE /pats/:id on the user router; adds Jest mock for the PAT controller with all three handlers stubbed to return { success: true }.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as CLI Client
  participant AuthMW as authenticateCLI
  participant Redis as Redis
  participant DB as Developer (MongoDB)
  participant Controller as PAT Controller

  rect rgba(173, 216, 230, 0.5)
    Note over CLI, Controller: PAT Creation
    CLI->>Controller: POST /pats (Bearer dashboard JWT)
    Controller->>DB: find Developer, push patSchema entry
    DB-->>Controller: saved developer
    Controller-->>CLI: { rawToken, suffix, ... } (once only)
  end

  rect rgba(144, 238, 144, 0.5)
    Note over CLI, Controller: CLI Request with PAT
    CLI->>AuthMW: GET /... Authorization: Bearer ubpat_live_*
    AuthMW->>AuthMW: SHA-256 hash token
    AuthMW->>Redis: GET cli:pat:cache:{hash}
    Redis-->>AuthMW: developerId or null
    AuthMW->>DB: findById, match PAT by tokenHash
    DB-->>AuthMW: Developer + PAT entry
    AuthMW->>DB: async update lastUsedAt/Ip
    AuthMW->>Controller: next() with req.developer, req.cliScopes
  end

  rect rgba(255, 182, 193, 0.5)
    Note over CLI, Controller: PAT Revocation
    CLI->>Controller: DELETE /pats/:id
    Controller->>DB: pull PAT, save developer
    Controller->>Redis: DEL cli:pat:cache:{tokenHash}
    Controller-->>CLI: { success: true }
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

feature, backend, intermediete-advance

Suggested reviewers

  • Nitin-kumar-yadav1307
  • yash-pouranik

Poem

🐇 A token is born from Base62 and chance,
Hashed with SHA-256 for a secure dance,
It rides the Redis cache with a ubpat_ prefix so fine,
Three endpoints to create, list, and revoke in a line.
The CLI hops in with a Bearer header at last—
This rabbit's PAT system is ready and fast! 🗝️

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Enabling pat backend clean' is vague and does not clearly summarize the main change; it lacks specificity about what PAT backend functionality is being implemented. Revise the title to be more descriptive and specific, such as 'Implement Personal Access Token (PAT) authentication for CLI tools' or 'Add PAT generation, validation middleware, and API endpoints'.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 7

🧹 Nitpick comments (1)
apps/dashboard-api/src/__tests__/routes.user.test.js (1)

45-50: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Add route-wiring assertions for the three new PAT endpoints.

This file mocks PAT handlers but doesn’t verify POST/GET/DELETE /api/user/pats* wiring yet. Adding 3 lightweight route tests would close that regression gap.

Example test additions
+const patController = require('../controllers/pat.controller');
+
+test('POST /api/user/pats is wired to authenticated createPAT', async () => {
+    const res = await request(app).post('/api/user/pats').send({ label: 'cli', scopes: ['read'] });
+    expect(res.status).toBe(200);
+    expect(authMiddleware).toHaveBeenCalledTimes(1);
+    expect(patController.createPAT).toHaveBeenCalledTimes(1);
+});
+
+test('GET /api/user/pats is wired to authenticated listPATs', async () => {
+    const res = await request(app).get('/api/user/pats');
+    expect(res.status).toBe(200);
+    expect(authMiddleware).toHaveBeenCalledTimes(1);
+    expect(patController.listPATs).toHaveBeenCalledTimes(1);
+});
+
+test('DELETE /api/user/pats/:id is wired to authenticated revokePAT', async () => {
+    const res = await request(app).delete('/api/user/pats/mock_pat_id');
+    expect(res.status).toBe(200);
+    expect(authMiddleware).toHaveBeenCalledTimes(1);
+    expect(patController.revokePAT).toHaveBeenCalledTimes(1);
+});
🤖 Prompt for 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.

In `@apps/dashboard-api/src/__tests__/routes.user.test.js` around lines 45 - 50,
Add three test cases after the mock definitions to verify route wiring for the
PAT endpoints. Create tests that make HTTP requests to POST /api/user/pats
(should trigger the mocked createPAT function), GET /api/user/pats (should
trigger the mocked listPATs function), and DELETE /api/user/pats/:id (should
trigger the mocked revokePAT function). Each test should verify that the
corresponding mocked handler function was called with the request and response
objects to ensure the routes are properly wired to their controller handlers.
🤖 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 `@apps/dashboard-api/src/controllers/pat.controller.js`:
- Around line 96-98: The PAT revocation persists to the database first, then
attempts Redis cache eviction using redis.del with the key
`cli:pat:cache:${patToRevoke.tokenHash}`. Since the database revoke is the
critical operation and the Redis deletion is just a cache optimization, handle
any Redis errors separately by logging them without failing the entire response.
Modify the error handling so that if the Redis deletion fails, the client still
receives a success response because the actual revocation already succeeded in
the database, rather than returning a 500 error that misrepresents the
operation's status.
- Around line 15-16: The TTL validation logic in the pat.controller.js file has
a flaw where the default value assignment using `const days = Number(ttlDays) ||
30;` occurs before validation, causing invalid input like ttlDays=0 to be
silently replaced with 30 instead of being rejected. Separate the defaulting and
validation logic by first checking if ttlDays is provided and valid (between 1
and 365), then applying the default value of 30 only when ttlDays is undefined,
null, or empty, ensuring the bounds check on line 16 properly catches all
invalid inputs before they become the final days value.
- Around line 37-38: Replace all instances of req.user.id with req.user._id in
the pat.controller.js file. The production JWT tokens use the _id field (as
defined in auth.controller.js), not id, so the three occurrences of req.user.id
at the affected lines (used in database query operations with $push, $inc, and
other update operators) must be changed to req.user._id to ensure proper
database lookups in production. This fix is necessary because the test suite
masks this issue by using _id in mock objects, but real JWT tokens will only
contain the _id field.

In `@apps/dashboard-api/src/middlewares/authenticateCLI.js`:
- Around line 28-48: The Redis cache operations (redis.get, redis.del, and
redis.setex) are awaited synchronously and can block authentication if Redis is
slow or unavailable. Wrap each Redis operation (the redis.get call at the
beginning, the redis.del call when developer is not found in cache, and the
redis.setex call when caching valid tokens) in separate try-catch blocks so that
Redis failures are non-blocking. When a Redis operation fails, log a warning but
allow the authentication flow to continue by falling through to database
validation. This ensures that authentication proceeds with database lookups even
when Redis is unavailable, making the cache truly best-effort rather than a
blocker for valid PAT authentication.
- Around line 50-52: In the authenticateCLI middleware where the matchedPat
validation check occurs, when matchedPat is falsy (indicating a revoked or
rotated token), the code should clear the stale cache entry before returning the
401 error. Modify the if (!matchedPat) block to delete the cached developerId
entry from the cache before calling next(new AppError(401, ...)) to prevent
repeated cache hits on subsequently invalid tokens. This allows the cache to
self-heal when a developer's token has been revoked or rotated.
- Line 2: The CACHE_TTL constant in the authenticateCLI.js file is being
assigned directly from the process.env.CLI_PAT_CACHE_TTL environment variable,
which is a string type. Since this value is passed to redis.setex() which
expects an integer for the TTL parameter, parse the environment variable to an
integer using parseInt() or Number() before assignment, maintaining the fallback
default of 300 if the environment variable is not set or is not a valid number.

In `@packages/common/src/models/Developer.js`:
- Around line 121-123: The pats field in the Developer model lacks an index on
the nested tokenHash field, causing collection scans when the auth middleware
queries on pats.tokenHash. Add a compound index on the pats.tokenHash field in
the Developer schema definition to optimize lookups. You can do this by adding
an index option to the pats field definition that creates an index specifically
for the tokenHash nested property within the pats array.

---

Nitpick comments:
In `@apps/dashboard-api/src/__tests__/routes.user.test.js`:
- Around line 45-50: Add three test cases after the mock definitions to verify
route wiring for the PAT endpoints. Create tests that make HTTP requests to POST
/api/user/pats (should trigger the mocked createPAT function), GET
/api/user/pats (should trigger the mocked listPATs function), and DELETE
/api/user/pats/:id (should trigger the mocked revokePAT function). Each test
should verify that the corresponding mocked handler function was called with the
request and response objects to ensure the routes are properly wired to their
controller handlers.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2e0e56c9-c40c-40bd-9ac4-cec416adca00

📥 Commits

Reviewing files that changed from the base of the PR and between da5670f and 44dfd21.

📒 Files selected for processing (7)
  • apps/dashboard-api/src/__tests__/routes.user.test.js
  • apps/dashboard-api/src/controllers/pat.controller.js
  • apps/dashboard-api/src/middlewares/authenticateCLI.js
  • apps/dashboard-api/src/routes/user.js
  • packages/common/src/index.js
  • packages/common/src/models/Developer.js
  • packages/common/src/utils/token.utils.js

Comment thread apps/dashboard-api/src/controllers/pat.controller.js Outdated
Comment thread apps/dashboard-api/src/controllers/pat.controller.js Outdated
Comment thread apps/dashboard-api/src/controllers/pat.controller.js
Comment thread apps/dashboard-api/src/middlewares/authenticateCLI.js Outdated
Comment thread apps/dashboard-api/src/middlewares/authenticateCLI.js Outdated
Comment thread apps/dashboard-api/src/middlewares/authenticateCLI.js
Comment thread packages/common/src/models/Developer.js
@Ayush4958

Copy link
Copy Markdown
Contributor Author

@yash-pouranik
This PR is ready for review

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant