Skip to content

Fix SSR auth for private repository pages#338

Open
manana2520 wants to merge 2 commits intoAIDotNet:mainfrom
keboola:upstream/ssr-auth
Open

Fix SSR auth for private repository pages#338
manana2520 wants to merge 2 commits intoAIDotNet:mainfrom
keboola:upstream/ssr-auth

Conversation

@manana2520
Copy link
Contributor

Summary

Private repositories show "Repository Not Found" when users navigate directly to a repo URL (e.g., /owner/repo) because Next.js Server Components call fetch without an Authorization header. The JWT token was stored only in localStorage, which is inaccessible during SSR.

Changes

web/lib/auth-api.ts

  • Store JWT in a cookie (deepwiki_token) alongside localStorage on login
  • Clear cookie on logout
  • Add getServerToken() that reads the cookie via next/headers during SSR

web/lib/repository-api.ts

  • Add getSSRAuthHeaders() helper that returns Authorization: Bearer <token> if a cookie is present
  • Inject auth headers in all SSR fetch functions: fetchRepoTree, fetchRepoBranches, fetchRepoDoc, checkGitHubRepo, fetchRepoStatus, fetchProcessingLogs, fetchRepositoryList, fetchGitBranches, fetchMindMap

How it works

  1. User logs in -> setToken() sets both localStorage and cookie
  2. User navigates to /owner/private-repo -> SSR calls fetchRepoTree()
  3. getSSRAuthHeaders() calls getServerToken() which reads cookie via next/headers
  4. Fetch includes Authorization: Bearer <jwt> header -> backend returns repo data
  5. On client side, getServerToken() returns null (window exists), so client-side auth continues via apiClient + localStorage as before

Test plan

  • Log in, navigate to private repo URL directly -> shows repo content
  • Open private repo URL in incognito (no login) -> shows "Repository Not Found"
  • Public repos still work without login
  • Log out, then navigate to private repo -> shows "Repository Not Found"

Private repos returned "Repository Not Found" on direct navigation because
SSR fetches had no Authorization header. JWT was stored only in localStorage,
which is inaccessible during server-side rendering.

- Store JWT in cookie alongside localStorage on login/logout
- Add getServerToken() to read cookie via next/headers during SSR
- Add getSSRAuthHeaders() helper in repository-api.ts
- Inject auth headers in all SSR fetch functions (fetchRepoTree,
  fetchRepoBranches, fetchRepoDoc, checkGitHubRepo, fetchRepoStatus,
  fetchProcessingLogs, fetchRepositoryList, fetchGitBranches, fetchMindMap)

On client side, getServerToken() returns null (window exists) so client-side
auth continues to work via apiClient and localStorage as before. No backend
changes needed - backend already handles Bearer tokens correctly.
getServerToken() was calling cookies() synchronously, but in Next.js 15+
cookies() returns a Promise. The function got a Promise object instead of
the cookie store, so the token was never read during SSR.

- Make getServerToken() async with await cookies()
- Make getSSRAuthHeaders() async
- Await getSSRAuthHeaders() in all fetch call sites
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