Skip to content

Add userId validation to subscription pause/resume endpoints#51

Open
Coponder wants to merge 3 commits intomainfrom
claude/address-issue-48-Zr7ov
Open

Add userId validation to subscription pause/resume endpoints#51
Coponder wants to merge 3 commits intomainfrom
claude/address-issue-48-Zr7ov

Conversation

@Coponder
Copy link
Collaborator

@Coponder Coponder commented Feb 5, 2026

Summary

Enhanced security for subscription pause and resume operations by adding explicit userId validation to both the frontend component and backend API endpoints. This ensures that users can only pause/resume their own subscriptions, while staff members can only perform these actions on behalf of users they're explicitly viewing as.

Key Changes

  • SubscriptionInfo component: Added userId prop and passed it to both pause and resume API requests
  • POST /pause-subscription endpoint:
    • Extract userId from request body
    • Validate that userId is provided
    • Authorize based on whether it's the user's own account or a staff member viewing as that user
    • Use validated userId instead of deriving it from session
  • DELETE /pause-subscription endpoint (resume):
    • Modified to accept request body with userId
    • Added same validation and authorization checks as POST endpoint
    • Consistent error handling and user notification logic
  • Portal page: Pass effectiveUserId to SubscriptionInfo component

Implementation Details

  • Authorization checks verify that userId matches either session.userId (own account) or session.viewingAsUserId (staff viewing as another user)
  • Returns 400 error if userId is missing, 403 if unauthorized
  • Simplified conditional logic by storing authorization results in isOwnAccount and isViewingAsTarget variables
  • Maintains existing notification behavior for both users and admins

https://claude.ai/code/session_01UCFbRRcHm9tQ3PfqLT8JC9

Previously, the pause subscription feature relied solely on session state
to determine which user to pause. When an admin was viewing as another
user, if the session's viewingAsUserId was stale or not properly synced
with the client, the pause action would fall back to the admin's own
userId, pausing their own subscription instead of the target user's.

This fix:
- Passes the explicit userId from the server-rendered page to the client
- Includes userId in pause/resume API requests
- Adds authorization checks to validate the userId matches either the
  caller's own account or their view-as target

https://claude.ai/code/session_01UCFbRRcHm9tQ3PfqLT8JC9
@vercel
Copy link
Contributor

vercel bot commented Feb 5, 2026

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

Project Deployment Actions Updated (UTC)
mox-sf Ready Ready Preview, Comment Feb 5, 2026 2:30am

Request Review

@claude
Copy link

claude bot commented Feb 5, 2026


Code review

No issues found. Checked for bugs and CLAUDE.md compliance.


@wearsshoes
Copy link
Collaborator

@claude this still doesn't seem to work; I tried again as Ventali while in admin mode as myself (Rachel Shu), and it paused me again rather than ventali. this might also be connected to an issue where when I refresh, it doesn't preserve the previous 'logged in as', but rather always resets to operating as myself

@claude
Copy link

claude bot commented Feb 5, 2026

Claude finished @wearsshoes's task in 2m 17s —— View job


Investigating subscription pause bug

  • Read the current implementation of pause/resume endpoints
  • Trace how userId is passed from frontend to backend
  • Add debug logging to identify the issue
  • Analyze logs after user testing
  • Fix the root cause
  • Test and commit final fix

Analysis

I've reviewed the code flow and the logic appears correct:

  1. Frontend (page.tsx:109): Correctly passes effectiveUserId (which is viewingAsUserId when in admin mode) to SubscriptionInfo
  2. Frontend (SubscriptionInfo.tsx:131): Correctly sends userId in the POST request body
  3. Backend (route.ts:178-195): Has authorization check that validates session.viewingAsUserId === userId
  4. Backend (route.ts:219): Uses the validated userId to fetch the correct user info via getUserInfo(userId)

Debug Logging Added

I've added comprehensive debug logging to both the POST (pause) and DELETE (resume) endpoints that will show:

  • What userId was sent in the request
  • What session.userId is (the logged-in admin's ID)
  • What session.viewingAsUserId is (should be Ventali's ID when viewing as them)
  • Whether the authorization checks pass
  • What user info was looked up (email, name, Stripe customer ID)

Next Steps

@wearsshoes Could you please try the pause operation again now that the debug logging is in place? The logs will help us see exactly what's happening. You should be able to see the logs in your terminal where the dev server is running (bun run codev logs to /tmp/dev-server.log), or check the Vercel deployment logs for this PR branch.

Once we see the logs, we'll be able to identify whether:

  1. The session is not preserving viewingAsUserId correctly
  2. The wrong userId is being sent from the frontend
  3. Something else is going wrong in the Stripe lookup

| Branch: claude/address-issue-48-Zr7ov

Co-authored-by: Rachel Shu <wearsshoes@users.noreply.github.com>
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.

3 participants