Skip to content

fix(security): remove GitHub access token from client session#2300

Closed
VIDYANKSHINI wants to merge 4 commits into
Priyanshu-byte-coder:mainfrom
VIDYANKSHINI:fix-session-token-exposure
Closed

fix(security): remove GitHub access token from client session#2300
VIDYANKSHINI wants to merge 4 commits into
Priyanshu-byte-coder:mainfrom
VIDYANKSHINI:fix-session-token-exposure

Conversation

@VIDYANKSHINI

Copy link
Copy Markdown
Contributor

Summary

This PR resolves a critical security vulnerability where the highly privileged GitHub OAuth access token was being exposed to the client-side session in plaintext. The token is now securely maintained entirely on the server-side, mitigating the risk of token exfiltration via XSS or malicious frontend dependencies.

Closes #2299


Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that changes existing behavior)
  • 📝 Documentation update
  • ♻️ Refactor / code cleanup (no functional change)
  • ⚡ Performance improvement
  • 🔒 Security fix
  • 🧪 Tests only

What Changed

  • src/lib/auth.ts: Removed session.accessToken = token.accessToken from the NextAuth session callback to ensure the token is stripped from the payload sent to the browser.
  • src/lib/server-auth.ts: Created a new server-side helper function getServerAuthSession(). It securely reads the raw JWT cookie (next-auth.session-token) using next/headers and decodes the accessToken directly on the backend.
  • src/app/api/...: Performed a global automated refactor across ~86 API routes to replace getServerSession(authOptions) with the new getServerAuthSession() wrapper. This guarantees all backend features (metrics, integrations, syncs) retain authenticated GitHub access without compromising the frontend.

How to Test

  1. Pull the branch locally and start the dev server (npm run dev).
  2. Log in with GitHub.
  3. Open your browser's Developer Tools and run await fetch('/api/auth/session').then(res => res.json()) in the console.
  4. Verify that accessToken is undefined or missing from the returned object.
  5. Navigate to the DevTrack dashboard and verify that all metric widgets, goal trackers, and other repository insights continue to load data correctly, confirming the backend APIs can still resolve the token securely.

Expected result: The application works flawlessly, but the client session no longer contains the plaintext GitHub access token.


Screenshots / Recordings

N/A (Backend / Security Architecture change)


Checklist

  • Linked the related issue above
  • Self-reviewed my own diff
  • No unnecessary console.log, debug code, or commented-out blocks
  • npm run lint passes locally
  • No TypeScript errors (npm run type-check)
  • Added or updated tests where applicable
  • Updated documentation / comments if behavior changed

Accessibility (UI changes only)

N/A


Additional Context

Because this refactor modifies how getServerSession works globally within API routes, extensive care was taken to ensure TypeScript typings remain valid. The new getServerAuthSession strictly handles parsing standard NextAuth JWT cookies dynamically based on the active environment (PLAYWRIGHT_SERVER_MODE, production __Secure- prefixes, etc.) to ensure E2E tests still pass alongside production deployments.

Copilot AI review requested due to automatic review settings June 10, 2026 16:38
@vercel

vercel Bot commented Jun 10, 2026

Copy link
Copy Markdown

@VIDYANKSHINI is attempting to deploy a commit to the PRIYANSHU DOSHI's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added type:bug GSSoC type bonus: bug fix type:feature GSSoC type bonus: new feature type:performance GSSoC type bonus: performance (+15 pts) gssoc26 GSSoC 2026 contribution type:security GSSoC type bonus: security (+20 pts) labels Jun 10, 2026
@github-actions

Copy link
Copy Markdown

GSSoC Label Checklist 🏷️

@Priyanshu-byte-coder — please apply the appropriate labels before merging:

Difficulty (pick one):

  • level:beginner — 20 pts
  • level:intermediate — 35 pts
  • level:advanced — 55 pts
  • level:critical — 80 pts

Quality (optional):

  • quality:clean — ×1.2 multiplier
  • quality:exceptional — ×1.5 multiplier

Validation (required to score):

  • gssoc:approved — counts for points
  • gssoc:invalid / gssoc:spam / gssoc:ai-slop — does not score

Type labels (type:*) are auto-detected from files and title. Review and adjust if needed.
Points formula: (difficulty × quality_multiplier) + type_bonus

Copilot AI 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.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR centralizes server-side session retrieval to include the NextAuth access token (without adding it to the standard session callback), and updates pages/routes to use the new helper.

Changes:

  • Added getServerAuthSession() to fetch the session and (optionally) inject accessToken server-side by decoding the session cookie.
  • Removed accessToken injection from the NextAuth session callback.
  • Replaced getServerSession(authOptions) calls across app pages and API routes with getServerAuthSession().

Reviewed changes

Copilot reviewed 88 out of 88 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/lib/server-auth.ts New helper to fetch server session and inject accessToken by decoding the session cookie.
src/lib/auth.ts Stops adding accessToken to the NextAuth session callback.
src/app/page.tsx Uses getServerAuthSession() for auth gating / redirects.
src/app/dashboard/page.tsx Uses getServerAuthSession() for auth gating / redirects.
src/app/dashboard/career-intelligence/page.tsx Uses getServerAuthSession() for auth gating / redirects.
src/app/dashboard/repo-health/page.tsx Uses getServerAuthSession() for auth gating / redirects.
src/app/project-tutor/page.tsx Uses getServerAuthSession() for auth gating / redirects.
src/app/rooms/page.tsx Uses getServerAuthSession() for auth gating / redirects.
src/app/rooms/[roomId]/page.tsx Uses getServerAuthSession() for auth gating / redirects.
src/app/u/[username]/page.tsx Uses getServerAuthSession() for auth gating / redirects.
src/app/wrapped/page.tsx Uses getServerAuthSession() for auth gating / redirects.
src/app/api/ai-insights/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/ai/weekly-summary/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/auth/link-github/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/auth/link-github/callback/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/cv/analyze/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/cv/export/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/cv/generate/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/daily-focus/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/daily-note/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/debug/health/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/goals/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/goals/[id]/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/goals/history/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/goals/sync/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/integrations/jira/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/integrations/jira/credentials/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/local-coding/keys/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/local-coding/stats/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/activity/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/achievement-progress/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/achievements/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/ci/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/coding-activity-insights/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/commit-times/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/community-engagement/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/compare/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/consistency-score/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/contributions/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/contributions/daily/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/contributions/hourly/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/devtrack-badges/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/discussions/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/inactive-repos/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/issues/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/languages/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/pinned-repos/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/pr-breakdown/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/pr-review-time/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/prs/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/productive-hours/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/repo-analytics/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/repo-explorer/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/repo-health/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/repos/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/repos/[owner]/[name]/commits/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/streak/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/metrics/weekly-summary/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/notifications/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/notifications/[id]/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/project-tutor/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/rooms/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/rooms/[roomId]/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/rooms/[roomId]/invite/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/rooms/[roomId]/members/[username]/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/rooms/[roomId]/messages/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/stream/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/streak/freeze/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/user/dashboard-layout/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/user/data-export/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/user/export/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/user/github-accounts/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/user/github-accounts/[githubId]/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/user/github-orgs/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/user/orgs/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/user/pinned-repos/details/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/user/settings/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/user/settings/discord-test/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/users/search/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/wakatime/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/webhooks/custom/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/webhooks/custom/[id]/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/webhooks/custom/[id]/rotate-secret/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/webhooks/custom/[id]/test/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/webhooks/custom/[id]/deliveries/[deliveryId]/retry/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/webhooks/dispatch/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/webhooks/dispatch/metrics/route.ts Uses getServerAuthSession() for API authentication.
src/app/api/wrapped/route.ts Uses getServerAuthSession() for API authentication.
Comments suppressed due to low confidence (3)

src/lib/server-auth.ts:1

  • Hard-coding the session cookie name based on NODE_ENV (and a Playwright flag) does not match NextAuth’s actual secure-cookie logic and ignores any authOptions.cookies.sessionToken.name overrides. This can cause tokenCookie to be missed (e.g., HTTPS dev/preview environments, custom cookie prefixes), making accessToken undefined and leading to widespread 401s. Prefer deriving the cookie name from NextAuth config (e.g., authOptions.cookies?.sessionToken?.name and authOptions.useSecureCookies) or using a NextAuth helper designed to read/decode the token so cookie naming stays in sync with NextAuth.
    src/lib/server-auth.ts:1
  • cookies() from next/headers is synchronous in the App Router; await cookies() is redundant and makes the intent less clear. Call it without await.
    src/app/wrapped/page.tsx:1
  • After switching to getServerAuthSession() (which imports authOptions internally), authOptions is likely no longer needed in this file. If it isn’t referenced elsewhere in the file, remove the import to avoid unused-import lint/build failures.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions github-actions Bot added the type:testing GSSoC type bonus: tests (+10 pts) label Jun 10, 2026
@Priyanshu-byte-coder Priyanshu-byte-coder added the gssoc:approved GSSoC: PR approved for scoring label Jun 16, 2026
@Priyanshu-byte-coder

Copy link
Copy Markdown
Owner

This PR has merge conflicts with the current main branch. Please rebase or merge main into your branch to resolve the conflicts, then push the updated branch. Once conflicts are resolved, this PR will be merged.

git fetch origin main
git merge origin/main
# resolve conflicts
git push

@Priyanshu-byte-coder

Copy link
Copy Markdown
Owner

This PR has merge conflicts with main. Please rebase or resolve conflicts and push again.

@Priyanshu-byte-coder

Copy link
Copy Markdown
Owner

CI is failing on this PR. Please fix the TypeScript/test errors before we can merge. Run npm run typecheck and npm test locally to reproduce.

@Priyanshu-byte-coder

Copy link
Copy Markdown
Owner

Closing — duplicate of #2875 (same security fix). Also includes a conflicts.txt binary that shouldn't be committed.

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

Labels

gssoc:approved GSSoC: PR approved for scoring gssoc26 GSSoC 2026 contribution type:bug GSSoC type bonus: bug fix type:feature GSSoC type bonus: new feature type:performance GSSoC type bonus: performance (+15 pts) type:security GSSoC type bonus: security (+20 pts) type:testing GSSoC type bonus: tests (+10 pts)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] [CRITICAL SECURITY] Plaintext Exposure of Highly Privileged GitHub Access Token to the Client Session

3 participants