Skip to content

Fix OAuth Errors and Integrate Credits Display#437

Merged
ngoiyaeric merged 1 commit into
feature/standard-tier-implementationfrom
fix-oauth-and-credits-integration-2704938752808797816
Jan 17, 2026
Merged

Fix OAuth Errors and Integrate Credits Display#437
ngoiyaeric merged 1 commit into
feature/standard-tier-implementationfrom
fix-oauth-and-credits-integration-2704938752808797816

Conversation

@google-labs-jules
Copy link
Copy Markdown
Contributor

@google-labs-jules google-labs-jules Bot commented Jan 17, 2026

User description

This pull request addresses the reported OAuth authentication errors and integrates the credit management UI.

Key changes:

  1. OAuth Callback Enhancement: Updated app/auth/callback/route.ts to log detailed error information when exchangeCodeForSession fails. It now also redirects to an error page with the error message as a query parameter for better visibility and debugging.
  2. Credits Display Integration: Added the CreditsDisplay component to the History sidebar (components/history.tsx), allowing users to see their remaining credits directly in the interface.
  3. Upgrade Flow Fix: Updated the PurchaseCreditsPopup to correctly handle the "Upgrade to Standard" action by redirecting users to the Stripe checkout URL.
  4. Environment Documentation: Updated .env.example to include NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY, ensuring that developers are aware of these critical requirements for authentication.
  5. Stripe Package Installation: Added the stripe package as a dependency to support future webhook and payment handling integrations.
  6. Clean Build & Config: Verified that the project builds successfully with bun run build and ensured that auto-generated or temporary files like dev_server.log and unintended changes to next-env.d.ts and tsconfig.json were excluded or reverted.

PR created automatically by Jules for task 2704938752808797816 started by @ngoiyaeric


PR Type

Bug fix, Enhancement


Description

  • Enhanced OAuth error handling with detailed logging and error page redirect

  • Integrated CreditsDisplay component into history sidebar for user visibility

  • Fixed upgrade button to redirect to Stripe checkout URL

  • Added Supabase environment variables documentation to .env.example

  • Installed stripe package for payment processing support


Diagram Walkthrough

flowchart LR
  OAuth["OAuth Callback<br/>Error Handling"] -->|"Log & Redirect"| ErrorPage["Error Page<br/>with Message"]
  Credits["CreditsDisplay<br/>Component"] -->|"Integrate"| Sidebar["History Sidebar"]
  Upgrade["Upgrade Button"] -->|"Redirect to"| Stripe["Stripe Checkout"]
  Env["Environment<br/>Variables"] -->|"Document"| Config[".env.example"]
  Package["stripe Package"] -->|"Install"| Dependencies["package.json"]
Loading

File Walkthrough

Relevant files
Bug fix
route.ts
Enhanced OAuth error logging and error page redirect         

app/auth/callback/route.ts

  • Inverted error check logic to handle errors explicitly
  • Added detailed error logging with message, status, name and code
    prefix
  • Implemented redirect to error page with encoded error message query
    parameter
  • Wrapped success logic in else block for clarity
+9/-1     
purchase-credits-popup.tsx
Implemented Stripe checkout redirect for upgrades               

components/credits/purchase-credits-popup.tsx

  • Replaced placeholder upgrade logic with actual Stripe checkout URL
  • Opens Stripe checkout in new browser tab on upgrade action
  • Closes popup after initiating upgrade flow
+4/-3     
Documentation
.env.example
Added Supabase environment variables documentation             

.env.example

  • Added Supabase configuration section with URL and anonymous key
    placeholders
  • Documented required environment variables for authentication setup
+4/-0     
Enhancement
history.tsx
Integrated CreditsDisplay into history sidebar                     

components/history.tsx

  • Added import for CreditsDisplay component
  • Integrated CreditsDisplay into SheetContent with bottom margin spacing
  • Positioned credits display above chat history in sidebar
+2/-0     
Dependencies
package.json
Added stripe package dependency                                                   

package.json

  • Added stripe package version 20.2.0 to dependencies
  • Positioned after sonner and before supabase in alphabetical order
+1/-0     

…display

- Improved error logging in auth callback to diagnose 401 Unauthorized issues.
- Integrated CreditsDisplay component into the history sidebar.
- Fixed the upgrade button in PurchaseCreditsPopup to redirect to Stripe checkout.
- Added required Supabase environment variables to .env.example.
- Installed the stripe package to support payment processing.
- Ensured successful production build and clean repository state.
@google-labs-jules
Copy link
Copy Markdown
Contributor Author

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Jan 17, 2026

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

Project Deployment Review Updated (UTC)
qcx Ready Ready Preview, Comment Jan 17, 2026 10:52am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 17, 2026

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Comment @coderabbitai help to get the list of available commands and usage tips.

@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@qodo-code-review
Copy link
Copy Markdown
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Sensitive data leakage

Description: The new logging and redirect may leak sensitive information by logging part of the OAuth
code, logging user PII (user.email), and embedding error.message into a URL query
parameter (/auth/auth-code-error?error=...), which can be captured by browser history,
referrers, analytics, or server logs.
route.ts [34-46]

Referred Code
if (error) {
  console.error('[Auth Callback] Exchange code error:', {
    message: error.message,
    status: error.status,
    name: error.name,
    code: code?.substring(0, 10) + '...'
  })
  return NextResponse.redirect(`${origin}/auth/auth-code-error?error=${encodeURIComponent(error.message)}`)
} else {
  try {
    const { data: { user }, error: userErr } = await supabase.auth.getUser()
    if (!userErr && user) {
      console.log('[Auth Callback] User signed in:', user.email)
Reverse tabnabbing

Description: Opening a new tab with window.open(stripeUrl, '_blank') without noopener,noreferrer
enables reverse tabnabbing, allowing the opened page to potentially control window.opener
and redirect the original page.
purchase-credits-popup.tsx [52-56]

Referred Code
const handleUpgrade = (tier: string) => {
    // Redirect to Stripe checkout
    const stripeUrl = 'https://buy.stripe.com/3cIaEX3tRcur9EM7ss';
    window.open(stripeUrl, '_blank');
    setIsOpen(false);
Reflected XSS risk

Description: Passing error.message via the error query parameter to an error page can become a
reflected XSS vector if that page renders the parameter without strict
escaping/sanitization.
route.ts [41-42]

Referred Code
  return NextResponse.redirect(`${origin}/auth/auth-code-error?error=${encodeURIComponent(error.message)}`)
} else {
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🔴
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Missing audit context: New authentication logging records a sign-in event but does not include a stable user
identifier and does not provide an audit-grade structured record to reconstruct who did
what and the outcome.

Referred Code
if (error) {
  console.error('[Auth Callback] Exchange code error:', {
    message: error.message,
    status: error.status,
    name: error.name,
    code: code?.substring(0, 10) + '...'
  })
  return NextResponse.redirect(`${origin}/auth/auth-code-error?error=${encodeURIComponent(error.message)}`)
} else {
  try {
    const { data: { user }, error: userErr } = await supabase.auth.getUser()
    if (!userErr && user) {
      console.log('[Auth Callback] User signed in:', user.email)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status:
Unused parameter: The new handleUpgrade(tier: string) implementation ignores the tier argument, making the
identifier misleading and the code less self-documenting.

Referred Code
const handleUpgrade = (tier: string) => {
    // Redirect to Stripe checkout
    const stripeUrl = 'https://buy.stripe.com/3cIaEX3tRcur9EM7ss';
    window.open(stripeUrl, '_blank');
    setIsOpen(false);
}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Unhandled popup failure: The new window.open flow does not handle the case where the browser blocks the popup
(returns null), so the upgrade action can fail silently without user feedback.

Referred Code
// Redirect to Stripe checkout
const stripeUrl = 'https://buy.stripe.com/3cIaEX3tRcur9EM7ss';
window.open(stripeUrl, '_blank');
setIsOpen(false);

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status:
Error exposed to user: The redirect appends error.message into a user-visible query parameter, potentially
exposing internal/auth provider details to end-users.

Referred Code
  return NextResponse.redirect(`${origin}/auth/auth-code-error?error=${encodeURIComponent(error.message)}`)
} else {

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Sensitive data in logs: New logs include user PII (user.email) and also log a substring of the OAuth authorization
code, both of which are sensitive and should not be written to application logs.

Referred Code
  console.error('[Auth Callback] Exchange code error:', {
    message: error.message,
    status: error.status,
    name: error.name,
    code: code?.substring(0, 10) + '...'
  })
  return NextResponse.redirect(`${origin}/auth/auth-code-error?error=${encodeURIComponent(error.message)}`)
} else {
  try {
    const { data: { user }, error: userErr } = await supabase.auth.getUser()
    if (!userErr && user) {
      console.log('[Auth Callback] User signed in:', user.email)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Reverse tabnabbing risk: The new window.open(stripeUrl, '_blank') call does not set noopener/noreferrer,
allowing the opened page to access window.opener and potentially manipulate the original
page.

Referred Code
const stripeUrl = 'https://buy.stripe.com/3cIaEX3tRcur9EM7ss';
window.open(stripeUrl, '_blank');

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@ngoiyaeric ngoiyaeric merged commit d6165e8 into feature/standard-tier-implementation Jan 17, 2026
4 of 5 checks passed
@qodo-code-review
Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Replace hardcoded URL with dynamic checkout

Replace the hardcoded Stripe URL with a call to a new server-side API endpoint
that generates a dynamic, user-specific Stripe Checkout session.

components/credits/purchase-credits-popup.tsx [53-56]

-// Redirect to Stripe checkout
-const stripeUrl = 'https://buy.stripe.com/3cIaEX3tRcur9EM7ss';
-window.open(stripeUrl, '_blank');
-setIsOpen(false);
+setLoading(true);
+try {
+  // Assumes an API route at /api/create-checkout-session
+  const response = await fetch('/api/create-checkout-session', {
+    method: 'POST',
+    headers: { 'Content-Type': 'application/json' },
+    body: JSON.stringify({ tier }), // Pass the selected tier
+  });
 
+  if (!response.ok) {
+    throw new Error('Failed to create checkout session.');
+  }
+
+  const { url: stripeUrl } = await response.json();
+  if (stripeUrl) {
+    window.open(stripeUrl, '_blank');
+  }
+} catch (error) {
+  console.error('Upgrade failed:', error);
+  // Optionally, show an error message to the user
+} finally {
+  setLoading(false);
+  setIsOpen(false);
+}
+
  • Apply / Chat
Suggestion importance[1-10]: 10

__

Why: The suggestion correctly identifies a critical flaw where a hardcoded Stripe URL prevents linking purchases to users, rendering the credit purchase feature non-functional.

High
Security
Avoid logging sensitive authentication tokens

Remove the code property from the console.error log object to avoid logging
sensitive authentication tokens.

app/auth/callback/route.ts [35-40]

 console.error('[Auth Callback] Exchange code error:', {
   message: error.message,
   status: error.status,
   name: error.name,
-  code: code?.substring(0, 10) + '...'
 })
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies that logging even a truncated authentication code is a security risk and should be avoided.

Medium
  • More

Copy link
Copy Markdown

@charliecreates charliecreates Bot left a comment

Choose a reason for hiding this comment

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

The OAuth callback now logs/propagates sensitive details: partial auth codes and provider error messages should not be logged or placed into redirect query strings. The Stripe upgrade flow is hard-coded and uses window.open without noopener,noreferrer, creating security and maintainability issues. The added stripe dependency appears unused in this diff and could become a client-bundling footgun unless kept strictly server-side.

Additional notes (1)
  • Maintainability | package.json:91-97
    Adding stripe increases bundle/install surface area. If it’s not yet used, consider adding it when server-side webhook/checkout session code lands, or ensure it’s only imported in server-only routes to prevent accidental client bundling.

As written, nothing in this diff shows usage, so this is potentially dead weight and a future footgun (someone might import it in a client component).

Summary of changes

Summary

This PR improves auth debuggability and integrates credit UI + payment plumbing:

  • Supabase env docs: Adds NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY to .env.example.
  • OAuth callback handling: In app/auth/callback/route.ts, logs richer details when exchangeCodeForSession fails and redirects to /auth/auth-code-error with an encoded error message.
  • Credits in sidebar: Injects <CreditsDisplay /> into the History sheet (components/history.tsx).
  • Upgrade flow: Changes PurchaseCreditsPopup to open a Stripe Checkout URL and closes the dialog.
  • Stripe dependency: Adds stripe to package.json (with corresponding lockfile change).

Comment on lines 33 to +42
const { error } = await supabase.auth.exchangeCodeForSession(code)
if (!error) {
if (error) {
console.error('[Auth Callback] Exchange code error:', {
message: error.message,
status: error.status,
name: error.name,
code: code?.substring(0, 10) + '...'
})
return NextResponse.redirect(`${origin}/auth/auth-code-error?error=${encodeURIComponent(error.message)}`)
} else {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The error log includes a derived code value (first 10 chars). Even partial authorization codes are sensitive and can end up in centralized logs (and potentially be replayable depending on provider/settings). This increases blast radius during incident triage.

Also, redirecting with the raw error.message in the query string can leak internal/provider details to the browser history, analytics, and referrers. Consider using a generic user-facing message (and keep details server-side), or pass a short error key/correlation id instead.

Suggestion

Consider removing the auth code from logs entirely and avoid placing error.message in the redirect URL. Example:

if (error) {
  const errorId = crypto.randomUUID();
  console.error('[Auth Callback] exchangeCodeForSession failed', {
    errorId,
    message: error.message,
    status: error.status,
    name: error.name,
  });
  return NextResponse.redirect(`${origin}/auth/auth-code-error?errorId=${errorId}`);
}

Then have the error page display a generic message and optionally show errorId for support.

Reply with "@CharlieHelps yes please" if you'd like me to add a commit with this suggestion.

Comment on lines 52 to +56
const handleUpgrade = (tier: string) => {
// Placeholder for upgrade logic
// In a real app, this would likely redirect to Stripe Checkout
console.log(`Upgrading to ${tier}`);
// Redirect to Stripe checkout
const stripeUrl = 'https://buy.stripe.com/3cIaEX3tRcur9EM7ss';
window.open(stripeUrl, '_blank');
setIsOpen(false);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

handleUpgrade ignores the tier parameter and uses a hard-coded Stripe URL. That makes the UI misleading (different tiers can’t map to different checkout sessions) and hard to change across environments.

Also, window.open(..., '_blank') without noopener,noreferrer enables reverse-tabnabbing. Some browsers mitigate this, but you shouldn’t rely on it.

Suggestion
  1. Remove the unused tier arg or actually use it to pick the correct destination.
  2. Prefer a same-tab navigation (window.location.assign) or set noopener,noreferrer.
  3. Avoid hard-coding: fetch a Checkout URL from your backend (creates a Stripe Checkout Session per user) or at least use an env var.

Example (minimal safer client-side change):

const handleUpgrade = () => {
  const stripeUrl = process.env.NEXT_PUBLIC_STRIPE_CHECKOUT_URL;
  if (!stripeUrl) return;
  window.open(stripeUrl, '_blank', 'noopener,noreferrer');
  setIsOpen(false);
};

Better: call /api/stripe/checkout to create a session and redirect to the returned URL.

Reply with "@CharlieHelps yes please" if you'd like me to add a commit with this suggestion.

@charliecreates charliecreates Bot removed the request for review from CharlieHelps January 17, 2026 11:24
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.

2 participants