Skip to content

fix: align export proxy auth contracts#403

Merged
jerry609 merged 1 commit into
devfrom
refactor/pr8-auth-proxy-contracts
Mar 15, 2026
Merged

fix: align export proxy auth contracts#403
jerry609 merged 1 commit into
devfrom
refactor/pr8-auth-proxy-contracts

Conversation

@jerry609

@jerry609 jerry609 commented Mar 15, 2026

Copy link
Copy Markdown
Owner

Summary

  • let web/src/app/api/_utils/auth-headers.ts fall back to PAPERBOT_API_BASE_URL, matching the rest of the web proxy layer and documented env contract
  • forward backend auth headers from web/src/app/api/papers/export/route.ts so the protected export endpoint can use the current user session
  • add focused vitest coverage for the auth helper and export proxy contract

Validation

  • cd web && npm install --no-audit --no-fund
  • cd web && npx vitest run src/app/api/_utils/auth-headers.test.ts src/app/api/papers/export/route.test.ts
  • cd web && npx eslint src/app/api/_utils/auth-headers.ts src/app/api/_utils/auth-headers.test.ts src/app/api/papers/export/route.ts src/app/api/papers/export/route.test.ts

Summary by CodeRabbit

  • Tests

    • Added comprehensive unit tests for authentication header handling and fallback URL resolution
    • Added integration tests for the papers export endpoint to verify proper authentication and header propagation
  • Bug Fixes

    • Enhanced authentication header handling to preserve existing headers and integrate server session tokens

Copilot AI review requested due to automatic review settings March 15, 2026 05:42
@vercel

vercel Bot commented Mar 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
paper-bot Ready Ready Preview, Comment Mar 15, 2026 5:43am

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request refines the authentication and base URL handling within the web API proxy layer. It standardizes the fallback mechanism for backend API URLs and ensures that protected endpoints, specifically the paper export functionality, correctly propagate user session authentication. These changes enhance the robustness and consistency of API interactions by aligning with established environment variable contracts and improving secure access to backend services.

Highlights

  • API Base URL Fallback: The backendBaseUrl utility now correctly falls back to PAPERBOT_API_BASE_URL if BACKEND_BASE_URL is not set, ensuring consistent environment contract usage across the web proxy layer.
  • Export Endpoint Authentication: The web/src/app/api/papers/export/route.ts endpoint has been updated to forward backend authentication headers, allowing the protected export endpoint to utilize the current user session.
  • New Test Coverage: Dedicated Vitest tests have been added for the auth-headers utility and the papers/export proxy route, improving code reliability and verifying the new authentication logic.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • web/src/app/api/_utils/auth-headers.test.ts
    • Added a new test file to provide focused Vitest coverage for the auth-headers utility.
    • Included tests for the backendBaseUrl function to verify its fallback logic for environment variables.
    • Implemented tests for the withBackendAuth function to ensure it correctly handles incoming authorization headers and server session access tokens.
  • web/src/app/api/_utils/auth-headers.ts
    • Introduced SessionMetadata type and readSessionMetadata function to safely extract session details.
    • Modified backendBaseUrl to prioritize BACKEND_BASE_URL but fall back to PAPERBOT_API_BASE_URL and then a default local URL.
    • Updated withBackendAuth to use the new readSessionMetadata function for accessing the session's access token, improving type safety and error handling.
  • web/src/app/api/papers/export/route.test.ts
    • Added a new test file to provide focused Vitest coverage for the papers/export proxy route.
    • Implemented a test to verify that the GET handler correctly forwards backend authentication headers to the protected export endpoint using withBackendAuth.
  • web/src/app/api/papers/export/route.ts
    • Imported the withBackendAuth utility function.
    • Modified the GET request handler to dynamically set authentication headers for the upstream fetch call using withBackendAuth, ensuring user session context is passed.
Activity
  • No human activity has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai

coderabbitai Bot commented Mar 15, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The pull request introduces authentication header utilities for server-side session token application with fallback support, including unit tests and integration with the papers export endpoint. The changes add session metadata handling, Authorization header preservation logic, and comprehensive test coverage for both authentication utilities and the export proxy endpoint.

Changes

Cohort / File(s) Summary
Authentication Headers Utilities
web/src/app/api/_utils/auth-headers.ts, web/src/app/api/_utils/auth-headers.test.ts
Introduces SessionMetadata type and readSessionMetadata helper for normalizing session objects. Modified backendBaseUrl to fallback to PAPERBOT_API_BASE_URL, and updated withBackendAuth to preserve existing Authorization headers while applying server-side session tokens with fallback logging. Comprehensive unit tests verify backendBaseUrl fallback behavior and withBackendAuth scenarios for both incoming and derived tokens.
Papers Export Endpoint
web/src/app/api/papers/export/route.ts, web/src/app/api/papers/export/route.ts
Updated GET route handler to use withBackendAuth for generating headers with proper authentication. Added test file verifying proxy header propagation, fetch method and headers, and preservation of response status, body, and headers (Content-Type and Content-Disposition).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Headers dance with auth so keen,
Sessions bloom in paths unseen,
Tests verify each guard so tight,
Tokens hop through exports bright! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: aligning authentication contracts in the export proxy by adding proper auth header forwarding.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/pr8-auth-proxy-contracts
📝 Coding Plan
  • Generate coding plan for human review comments

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.

@github-actions

Copy link
Copy Markdown

Vercel Preview

@sonarqubecloud

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request effectively aligns authentication contracts for the export proxy by updating the base URL fallback logic and ensuring authentication headers are forwarded correctly. The changes improve type safety with the new readSessionMetadata utility, and the new tests provide good coverage. My review includes a couple of suggestions to refactor the tests to use more idiomatic Vitest mocking patterns, which will improve their maintainability.

Comment on lines +17 to +29
afterEach(() => {
if (originalBackendBaseUrl === undefined) {
delete process.env.BACKEND_BASE_URL
} else {
process.env.BACKEND_BASE_URL = originalBackendBaseUrl
}

if (originalPaperbotApiBaseUrl === undefined) {
delete process.env.PAPERBOT_API_BASE_URL
} else {
process.env.PAPERBOT_API_BASE_URL = originalPaperbotApiBaseUrl
}
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The manual restoration of environment variables in afterEach is verbose and can be simplified using Vitest's vi.stubEnv and vi.unstubAllEnvs. This makes the test setup cleaner and less prone to errors.

Your test case can be updated to use vi.stubEnv to set variables, and this afterEach block can be simplified to just call vi.unstubAllEnvs().

Example of updated test case:

it("falls back to PAPERBOT_API_BASE_URL when BACKEND_BASE_URL is unset", () => {
  delete process.env.BACKEND_BASE_URL;
  vi.stubEnv("PAPERBOT_API_BASE_URL", "https://paperbot-api.example.com");

  expect(backendBaseUrl()).toBe("https://paperbot-api.example.com");
});
  afterEach(() => {
    vi.unstubAllEnvs()
  })

Comment on lines +24 to +26
afterEach(() => {
global.fetch = originalFetch
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Instead of manually saving and restoring global.fetch, it's better to use Vitest's built-in mocking capabilities. You can use vi.spyOn(global, 'fetch') to mock fetch within your test, and then call vi.restoreAllMocks() here to automatically clean up.

This would look like this in your test:

const fetchSpy = vi.spyOn(global, 'fetch').mockResolvedValue(
  new Response("bibtex-body", {
    status: 200,
    headers: {
      "content-type": "application/x-bibtex",
      "content-disposition": "attachment; filename=papers.bib",
    },
  }),
);

This avoids direct manipulation of global objects and the type casting.

Suggested change
afterEach(() => {
global.fetch = originalFetch
})
afterEach(() => {
vi.restoreAllMocks()
})

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

Aligns the Next.js web proxy layer’s auth/header behavior with the documented env contract and ensures the papers export proxy forwards the active user session to the protected backend export endpoint.

Changes:

  • Forward backend auth headers in the /api/papers/export proxy route via withBackendAuth.
  • Update backendBaseUrl() to fall back to PAPERBOT_API_BASE_URL when BACKEND_BASE_URL is unset.
  • Add focused Vitest coverage for the auth header helper and export proxy behavior.

Reviewed changes

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

File Description
web/src/app/api/papers/export/route.ts Forwards backend auth headers when proxying export requests.
web/src/app/api/papers/export/route.test.ts Tests that export proxy calls withBackendAuth and forwards returned headers to fetch.
web/src/app/api/_utils/auth-headers.ts Adds PAPERBOT_API_BASE_URL fallback and safer session metadata extraction for auth header forwarding.
web/src/app/api/_utils/auth-headers.test.ts Tests base URL fallback and auth header selection precedence.

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

You can also share your feedback on Copilot code review. Take the survey.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/src/app/api/_utils/auth-headers.ts (1)

35-40: ⚠️ Potential issue | 🔴 Critical

Do not trust client Authorization by default in proxy auth helper.

Line 37–39 returns early with caller-controlled credentials, which lets requests choose upstream identity instead of enforcing the current server session. This weakens auth boundaries for every route that uses this helper (including the shared research proxy base).

🔒 Suggested hardening (secure default + explicit opt-in)
 export async function withBackendAuth(
   req: Request,
   base: HeadersInit = {},
+  options: { allowIncomingAuthorization?: boolean } = {},
 ): Promise<HeadersInit> {
   const headers = new Headers(base)

   // Prefer client-provided Authorization header if present
   const incoming = req.headers.get("authorization")
-  if (incoming) {
+  if (options.allowIncomingAuthorization && incoming) {
     headers.set("authorization", incoming)
     return headers
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/app/api/_utils/auth-headers.ts` around lines 35 - 40, The helper
currently returns early and trusts caller-controlled incoming auth via
req.headers.get("authorization") (variables: incoming, headers), which lets
clients override the server session; change this to a secure default: do not set
or return the incoming Authorization header unless an explicit opt-in flag is
passed (e.g., allowClientAuthorization) to the function and the header is
validated against the server session or a strict whitelist; remove the early
return, use the server-derived session/token as the default value, and only
override headers.set("authorization", incoming) when the explicit flag is true
and validation succeeds so upstream identity cannot be chosen by the client.
🧹 Nitpick comments (1)
web/src/app/api/papers/export/route.test.ts (1)

18-18: Use globalThis instead of global for fetch stubbing/restoration.

Replace all three instances of global.fetch with globalThis.fetch (lines 18, 25, 43). The globalThis reference is the standardized, environment-agnostic way to access the global object and aligns with TypeScript and linter best practices.

♻️ Suggested update
-  const originalFetch = global.fetch
+  const originalFetch = globalThis.fetch
...
-    global.fetch = originalFetch
+    globalThis.fetch = originalFetch
...
-    global.fetch = fetchMock as typeof fetch
+    globalThis.fetch = fetchMock as typeof fetch
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/app/api/papers/export/route.test.ts` at line 18, Replace usages of
global.fetch with globalThis.fetch in the test where fetch is saved, stubbed and
restored: update the declaration that captures the original fetch
(originalFetch), the place where fetch is mocked/assigned for the test, and
where it is restored after tests; specifically change references in the
setup/teardown around originalFetch and any direct global.fetch assignments to
use globalThis.fetch to be environment-agnostic and satisfy TypeScript/linter
expectations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@web/src/app/api/_utils/auth-headers.ts`:
- Around line 35-40: The helper currently returns early and trusts
caller-controlled incoming auth via req.headers.get("authorization") (variables:
incoming, headers), which lets clients override the server session; change this
to a secure default: do not set or return the incoming Authorization header
unless an explicit opt-in flag is passed (e.g., allowClientAuthorization) to the
function and the header is validated against the server session or a strict
whitelist; remove the early return, use the server-derived session/token as the
default value, and only override headers.set("authorization", incoming) when the
explicit flag is true and validation succeeds so upstream identity cannot be
chosen by the client.

---

Nitpick comments:
In `@web/src/app/api/papers/export/route.test.ts`:
- Line 18: Replace usages of global.fetch with globalThis.fetch in the test
where fetch is saved, stubbed and restored: update the declaration that captures
the original fetch (originalFetch), the place where fetch is mocked/assigned for
the test, and where it is restored after tests; specifically change references
in the setup/teardown around originalFetch and any direct global.fetch
assignments to use globalThis.fetch to be environment-agnostic and satisfy
TypeScript/linter expectations.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 47f09541-1284-4b04-8d84-c083b456a6e0

📥 Commits

Reviewing files that changed from the base of the PR and between 751bcb2 and cce26d4.

📒 Files selected for processing (4)
  • web/src/app/api/_utils/auth-headers.test.ts
  • web/src/app/api/_utils/auth-headers.ts
  • web/src/app/api/papers/export/route.test.ts
  • web/src/app/api/papers/export/route.ts

@jerry609
jerry609 merged commit 8c77b6d into dev Mar 15, 2026
18 checks passed
@jerry609
jerry609 deleted the refactor/pr8-auth-proxy-contracts branch March 15, 2026 06:02
wen-placeholder pushed a commit to wen-placeholder/PaperBot that referenced this pull request Mar 17, 2026
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.

2 participants