Skip to content

feat(security): Move API Key to Cookies#243

Merged
Ayush8923 merged 5 commits into
mainfrom
feat/move-api-key-cookies
Jul 3, 2026
Merged

feat(security): Move API Key to Cookies#243
Ayush8923 merged 5 commits into
mainfrom
feat/move-api-key-cookies

Conversation

@Ayush8923

@Ayush8923 Ayush8923 commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Issue

Closes #224

Summary

  • Move API Key Token Storage from LocalStorage to Cookies.
  • Improve security by utilizing cookies for token storage.
  • Removed key visibility and copy controls from the keystore view for a cleaner experience.

Checklist

Before submitting a pull request, please ensure that you mark these task.

  • Ran npm run dev and npm run build in the repository root and test.
  • If you've fixed a bug or added code that is tested

@Ayush8923 Ayush8923 self-assigned this Jul 2, 2026
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

API key handling now uses server-managed cookies instead of localStorage. The PR adds API-key create/delete routes, updates AuthContext and keystore UI flows, and changes shared server clients to read API keys from headers or cookies.

Changes

API key storage migration to cookies

Layer / File(s) Summary
Contracts and cookie names
app/lib/constants.ts, app/lib/types/credentials.ts, app/lib/types/auth.ts, app/lib/utils.ts
Updates API key and auth types, adds cookie-name and max-age constants, and replaces client storage access with cookie reading.
API key cookie helpers and logout clearing
app/lib/authCookie.ts, app/api/auth/logout/route.ts
Adds API-key cookie set and clear helpers, switches auth cookie max-age handling to the shared constant, and clears API-key cookies during logout.
API key route and shared request auth
app/api/apikeys/route.ts, app/lib/apiClient.ts, app/lib/guardrailsClient.ts, app/api/evaluations/stt/runs/route.ts
Adds API-key create and delete handlers, masks returned keys, and updates shared server clients to obtain API keys through the new helper.
AuthContext server-backed key state
app/lib/context/AuthContext.tsx, CLAUDE.md
Hydrates API keys from a client cookie, replaces local persistence with server-backed add and remove calls, changes logout redirect, removes setKeys, and updates the auth docs example.
Keystore page and components
app/(main)/keystore/page.tsx, app/components/keystore/AddKeyModal.tsx, app/components/keystore/KeysCard.tsx
Rewires the keystore page to use server-backed add and delete actions, removes visibility and copy state, renders masked key values, and updates the add-key modal copy and provider field.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant KeystorePage
  participant AuthContext
  participant ApiKeysRoute
  participant BackendAPI

  KeystorePage->>AuthContext: addKey({ key, label })
  AuthContext->>ApiKeysRoute: POST /api/apikeys
  ApiKeysRoute->>BackendAPI: verify key (X-API-KEY, cookies)
  BackendAPI-->>ApiKeysRoute: verification result
  ApiKeysRoute-->>AuthContext: ApiKeyMeta + Set-Cookie
  AuthContext-->>KeystorePage: updated apiKeys state
Loading

Possibly related PRs

Suggested reviewers: Prajna1999, vprashrex

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR moves API key token storage from localStorage to cookies as requested in #224.
Out of Scope Changes check ✅ Passed The changes are focused on cookie-based API key storage and supporting auth plumbing, with no obvious unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: moving API key storage from localStorage to cookies for security.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/move-api-key-cookies

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.

@github-actions github-actions Bot changed the title Authentication: Move API Key Token Storage form LocalStorage to Cookies feat(security): Move API Key to Cookies Jul 2, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🧹 Nitpick comments (1)
app/api/apikeys/route.ts (1)

40-48: 🔒 Security & Privacy | 🔵 Trivial

No rate limiting around key verification.

This endpoint acts as an oracle: repeated calls with different candidate keys reveal validity via the 200/401 response, enabling brute-force enumeration of valid API keys since there's no throttling visible in this route.

🤖 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 `@app/api/apikeys/route.ts` around lines 40 - 48, Add rate limiting to the API
key verification flow in the apikeys route so repeated verification attempts
cannot be used as an oracle. Update the handler that calls apiClient for
"/api/v1/apikeys/verify" to consult the existing throttling mechanism before
making the backend request, and return an appropriate limited response when the
caller exceeds the allowed attempts. Keep the fix localized to the route handler
and its verification path so the 200/401 behavior is preserved for legitimate
requests but abuse is blocked.
🤖 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/`(main)/keystore/page.tsx:
- Around line 62-63: `handleDeleteKey` is still calling the key-removal flow
with an `id`, but the updated AuthContext `removeKey` now clears the single
cookie-backed key and takes no arguments. Update the delete handler in
`page.tsx` to stop passing the key id, and make sure the call site uses the
context-backed `removeKey` API consistently with the current `AuthContext`
contract.

In `@app/api/apikeys/route.ts`:
- Around line 22-24: The API key metadata flow is allowing an unbounded label to
be stored in the cookie, which can overflow browser cookie limits and break
client hydration. Update the `label` handling in `route.ts` and the
`COOKIE_KEYS.API_KEY_META` write path so `label` is capped to a reasonable
maximum before `JSON.stringify(meta)` is called, and make sure the same limit is
enforced anywhere the metadata is created or updated (including the save/update
logic referenced by the review).
- Around line 40-55: The verification flow in apikeys/route.ts is treating every
non-2xx response from apiClient in the same way, so backend 5xx outages are
being reported as an invalid key. Update the logic around the verifyRequest call
in the route handler to distinguish client-side auth failures from
server-side/backend failures by checking the returned status before mapping it
to a response: keep the 401 “invalid key” path only for auth-related statuses,
and return a backend/unavailable error for 5xx (or other non-auth) statuses,
while preserving the existing catch block for request/transport failures.
- Around line 11-68: The POST handler in apikeys/route.ts writes API key cookies
after successful verification without any CSRF/origin protection, so add an
Origin/Host check or CSRF token validation before calling setApiKeyCookies. Keep
the validation near the start of POST, before apiClient verification and cookie
writes, and reject requests with a 403 when the origin does not match the
expected site.

In `@app/components/keystore/KeysCard.tsx`:
- Around line 46-47: The security copy in KeysCard should not say the key is
stored server-side, since the raw key is actually placed in an HttpOnly cookie.
Update the user-facing message in the KeysCard component to accurately describe
the storage model while keeping the warning that the key cannot be viewed again
after it is added. Use the existing text block in KeysCard to adjust the copy
only, without changing the underlying key handling logic.

In `@app/lib/apiClient.ts`:
- Around line 6-12: The readCookieHeader helper in apiClient.ts currently calls
decodeURIComponent directly on request-controlled cookie values, which can throw
on malformed escapes and crash the route. Update readCookieHeader to safely
handle decoding failures by catching errors around the decode step (or otherwise
validating the value first) and treating bad cookie values as missing/invalid so
the function returns no usable cookie instead of throwing.

In `@app/lib/constants.ts`:
- Around line 27-35: The role and features cookie helpers still hardcode the
7-day max age instead of reusing the shared constant. Update the cookie-setting
logic in authCookie to use AUTH_COOKIE_MAX_AGE for both the role and features
cookies, and keep COOKIE_KEYS as the source for the cookie names so the lifetime
remains centralized.

In `@app/lib/context/AuthContext.tsx`:
- Around line 96-121: Route the API-key mutation calls in AuthContext through
clientFetch instead of direct fetch so shared 401 handling, AUTH_EXPIRED_EVENT
dispatching, and standardized error extraction are preserved. Update addKey and
removeKey to use clientFetch for the /api/apikeys POST and DELETE requests, and
ensure removeKey only clears api keys and dispatches kaapi-auth-changed after a
successful response. Keep the logic around setApiKeys, body.data validation, and
the kaapi-auth-changed event, but make success handling depend on clientFetch
returning without error.
- Around line 38-39: The API-key metadata parse in AuthContext.tsx should not
abort session hydration if COOKIE_KEYS.API_KEY_META is malformed. Update the
readClientCookie/JSON.parse(rawMeta) handling inside the AuthContext
initialization logic so parse failures are caught and ignored locally, allowing
the localStorage session restore that follows to still run. Keep the valid
setApiKeys path for well-formed metadata, but isolate it from the broader
hydration flow.

In `@app/lib/utils.ts`:
- Around line 72-80: The cookie parsing in readClientCookie can throw a URIError
when decodeURIComponent sees malformed client-controlled data. Update
readClientCookie to treat decoding as non-throwing by guarding the decode step
with error handling and returning undefined on decode failures, while keeping
the existing undefined return for missing cookies and server-side access.

---

Nitpick comments:
In `@app/api/apikeys/route.ts`:
- Around line 40-48: Add rate limiting to the API key verification flow in the
apikeys route so repeated verification attempts cannot be used as an oracle.
Update the handler that calls apiClient for "/api/v1/apikeys/verify" to consult
the existing throttling mechanism before making the backend request, and return
an appropriate limited response when the caller exceeds the allowed attempts.
Keep the fix localized to the route handler and its verification path so the
200/401 behavior is preserved for legitimate requests but abuse is blocked.
🪄 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: 772a3816-2fe4-4c7e-886e-22a6c28ff571

📥 Commits

Reviewing files that changed from the base of the PR and between 78e695f and adee97e.

📒 Files selected for processing (15)
  • CLAUDE.md
  • app/(main)/keystore/page.tsx
  • app/api/apikeys/route.ts
  • app/api/auth/logout/route.ts
  • app/api/evaluations/stt/runs/route.ts
  • app/components/keystore/AddKeyModal.tsx
  • app/components/keystore/KeysCard.tsx
  • app/lib/apiClient.ts
  • app/lib/authCookie.ts
  • app/lib/constants.ts
  • app/lib/context/AuthContext.tsx
  • app/lib/guardrailsClient.ts
  • app/lib/types/auth.ts
  • app/lib/types/credentials.ts
  • app/lib/utils.ts
💤 Files with no reviewable changes (1)
  • app/components/keystore/AddKeyModal.tsx

Comment thread app/(main)/keystore/page.tsx
Comment thread app/api/apikeys/route.ts
Comment thread app/api/apikeys/route.ts Outdated
Comment thread app/api/apikeys/route.ts
Comment thread app/components/keystore/KeysCard.tsx Outdated
Comment thread app/lib/apiClient.ts
Comment thread app/lib/constants.ts
Comment thread app/lib/context/AuthContext.tsx
Comment thread app/lib/context/AuthContext.tsx Outdated
Comment thread app/lib/utils.ts
Comment thread app/components/keystore/KeysCard.tsx Outdated
<InlineNotice>
Only one API key can be stored at a time. Delete this key to add a
different one.
different one. For your security, the key is stored server-side and

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this extra information are not needed to tell

Comment thread app/lib/types/credentials.ts Outdated
export interface ApiKeyMeta {
id: string;
label: string;
provider: string;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

why need to store provider in api key metadata ?

@Ayush8923 Ayush8923 Jul 3, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

basically this is not needed for now, but if we add more provider later then it's use. Right now, this is not needed so dropping it.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

what type of provider u mean ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

So previously it's a dropdown and I'm thinking like future providers, grouped by the modalities this app already handles (text / STT / TTS / observability). But not needed for now I have removed this. Thanks for pointing this out.

@vprashrex

Copy link
Copy Markdown
Collaborator

Instead of storing the raw API key in the cookie, I'd recommend using a session_id or a signed JWT instead. That said, implementing a session-based flow for API key authentication adds a fair amount of complexity. If it's not a priority right now, we can take it up later or leave it as is for the time being.

@Ayush8923

Copy link
Copy Markdown
Collaborator Author

Instead of storing the raw API key in the cookie, I'd recommend using a session_id or a signed JWT instead. That said, implementing a session-based flow for API key authentication adds a fair amount of complexity. If it's not a priority right now, we can take it up later or leave it as is for the time being.

I think for now, we can ship this current httpOnly-cookie approach now, it's a large, correct step up from localStorage and closes the XSS hole. for implement this session_id or signed JWT some backend changes required maybe so we can implement this later.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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/components/keystore/AddKeyModal.tsx`:
- Around line 39-41: The AddKeyModal copy incorrectly says keys are “stored
securely server-side,” but the actual storage model is an HttpOnly cookie;
update the descriptive text in AddKeyModal to match the same cookie-based
wording used in KeysCard and remove any server-side persistence claim.
🪄 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: b17080bb-f9cc-458f-86d0-5ea5926a18c2

📥 Commits

Reviewing files that changed from the base of the PR and between 195d137 and 8dac10b.

📒 Files selected for processing (7)
  • app/(main)/keystore/page.tsx
  • app/api/apikeys/route.ts
  • app/components/keystore/AddKeyModal.tsx
  • app/components/keystore/KeysCard.tsx
  • app/lib/context/AuthContext.tsx
  • app/lib/types/auth.ts
  • app/lib/types/credentials.ts
💤 Files with no reviewable changes (2)
  • app/api/apikeys/route.ts
  • app/lib/types/credentials.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • app/lib/context/AuthContext.tsx
  • app/lib/types/auth.ts
  • app/(main)/keystore/page.tsx

Comment thread app/components/keystore/AddKeyModal.tsx
@Ayush8923 Ayush8923 merged commit 9517392 into main Jul 3, 2026
2 checks passed
@Ayush8923 Ayush8923 deleted the feat/move-api-key-cookies branch July 3, 2026 08:12
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 0.3.0-main.8 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Authentication: Move API Key Token Storage form LocalStorage to Cookies

2 participants