[GH-ISSUE #3979] User can't be subscribed to multiple plans even if different reference ids are provided. #9783

Closed
opened 2026-04-13 05:29:35 -05:00 by GiteaMirror · 5 comments
Owner

Originally created by @aniravi24 on GitHub (Aug 13, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/3979

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

Have a user try to subscribe to two different plans at the same time, given different reference ids.

Current vs. Expected behavior

It forces the user to go to the upgrade flow and change their existing plan instead of being able to subscribe to both.

What version of Better Auth are you using?

1.3.4

System info

System:
    OS: Linux
    Shell: zsh
  Browsers:
    Chrome
    Chromium

Which area(s) are affected? (Select all that apply)

Backend

Auth config (if applicable)


Additional context

https://github.com/better-auth/better-auth/blob/canary/packages/stripe/src/index.ts#L331

I believe the offending code is somewhere around here, where we force customers to go through the upgrade flow as long as they any active subscription even if it's not the one I want to upgrade.

Originally created by @aniravi24 on GitHub (Aug 13, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/3979 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce Have a user try to subscribe to two different plans at the same time, given different reference ids. ### Current vs. Expected behavior It forces the user to go to the upgrade flow and change their existing plan instead of being able to subscribe to both. ### What version of Better Auth are you using? 1.3.4 ### System info ```bash System: OS: Linux Shell: zsh Browsers: Chrome Chromium ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript ``` ### Additional context https://github.com/better-auth/better-auth/blob/canary/packages/stripe/src/index.ts#L331 I believe the offending code is somewhere around here, where we force customers to go through the upgrade flow as long as they any active subscription even if it's not the one I want to upgrade.
GiteaMirror added the lockedbug labels 2026-04-13 05:29:36 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Aug 13, 2025):

Better Auth v1.3.4 does not support multiple active subscriptions per user/customer, even if you provide different reference IDs. The backend logic in the Stripe integration checks for any active or trialing subscription for the Stripe customer and, if found, forces the user into an upgrade flow instead of allowing a new subscription to be created. This means you can't subscribe to two different plans at the same time; the system always treats it as an upgrade or change to the existing plan, regardless of the reference ID you pass (code reference, issue #3690).

This is a known limitation and has been discussed in several issues (#1761, #3393). There is no official config option in v1.3.4 to enable multi-plan subscriptions per user. The recommended workaround is to scope subscriptions to organizations by using organization-level Stripe customers and passing the organization ID as the referenceId, but this requires custom configuration and may not be fully supported in all plugin versions (discussion). If you need true multi-plan support for users, you would need to customize the subscription logic or use hooks to manage multiple subscriptions manually.

Let me know if you want more details on how to implement a custom workaround or need code pointers for modifying the upgrade flow.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3184896063 --> @dosubot[bot] commented on GitHub (Aug 13, 2025): <!-- Answer --> Better Auth v1.3.4 does not support multiple active subscriptions per user/customer, even if you provide different reference IDs. The backend logic in the Stripe integration checks for any active or trialing subscription for the Stripe customer and, if found, forces the user into an upgrade flow instead of allowing a new subscription to be created. This means you can't subscribe to two different plans at the same time; the system always treats it as an upgrade or change to the existing plan, regardless of the reference ID you pass ([code reference](https://github.com/better-auth/better-auth/blob/c7a272f26137bb1eeafae267d460fc105f4ad714/packages/stripe/src/index.ts#L331), [issue #3690](https://github.com/better-auth/better-auth/issues/3690)). This is a known limitation and has been discussed in several issues ([#1761](https://github.com/better-auth/better-auth/issues/1761), [#3393](https://github.com/better-auth/better-auth/issues/3393)). There is no official config option in v1.3.4 to enable multi-plan subscriptions per user. The recommended workaround is to scope subscriptions to organizations by using organization-level Stripe customers and passing the organization ID as the referenceId, but this requires custom configuration and may not be fully supported in all plugin versions ([discussion](https://github.com/better-auth/better-auth/issues/3690)). If you need true multi-plan support for users, you would need to customize the subscription logic or use hooks to manage multiple subscriptions manually. Let me know if you want more details on how to implement a custom workaround or need code pointers for modifying the upgrade flow. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/6b0eaeb8-aa73-4a00-abcd-d724410ac6ee?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/6b0eaeb8-aa73-4a00-abcd-d724410ac6ee?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/6b0eaeb8-aa73-4a00-abcd-d724410ac6ee?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/6b0eaeb8-aa73-4a00-abcd-d724410ac6ee?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/6b0eaeb8-aa73-4a00-abcd-d724410ac6ee?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/6b0eaeb8-aa73-4a00-abcd-d724410ac6ee?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/6b0eaeb8-aa73-4a00-abcd-d724410ac6ee?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/3979)
Author
Owner

@aniravi24 commented on GitHub (Aug 13, 2025):

@dosu If the code I linked to has a more relaxed lookup where it actually checks the subscription ids, then all of the flows work as expected. The issue is specifically that this upgrade endpoint is assuming a user can only be subscribed to a single plan but the code does support having multiple reference ids (and therefore multiple subscriptions) when that section of code is fixed.

<!-- gh-comment-id:3184909118 --> @aniravi24 commented on GitHub (Aug 13, 2025): @dosu If the code I linked to has a more relaxed lookup where it actually checks the subscription ids, then all of the flows work as expected. The issue is specifically that this upgrade endpoint is assuming a user can only be subscribed to a single plan but the code does support having multiple reference ids (and therefore multiple subscriptions) when that section of code is fixed.
Author
Owner

@dosubot[bot] commented on GitHub (Aug 13, 2025):

You're correct—the upgrade endpoint currently assumes a user can only have one active subscription, but the rest of the codebase (including creation, cancellation, and listing endpoints) already supports multiple subscriptions per user when you differentiate by referenceId or subscriptionId. If you relax the lookup in the upgrade logic to check for the specific subscription ID (rather than any active subscription), all flows should work as expected for multiple concurrent subscriptions with different reference IDs. This is supported by recent changes in the codebase and PRs that move toward filtering and matching by subscription ID and reference ID, not just by customer ID alone (example).

If you make this change, review related endpoints (like cancellation and restoration) to ensure they're also referenceId- and subscriptionId-aware, but there are no deep blockers in the Stripe integration itself—it's an application-layer restriction. The modular structure means you can localize your changes to the relevant subscription management functions (source).

There’s no official documentation for this yet, so thorough testing is recommended if you relax this restriction.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3184937817 --> @dosubot[bot] commented on GitHub (Aug 13, 2025): <!-- Answer --> You're correct—the upgrade endpoint currently assumes a user can only have one active subscription, but the rest of the codebase (including creation, cancellation, and listing endpoints) already supports multiple subscriptions per user when you differentiate by `referenceId` or `subscriptionId`. If you relax the lookup in the upgrade logic to check for the specific subscription ID (rather than any active subscription), all flows should work as expected for multiple concurrent subscriptions with different reference IDs. This is supported by recent changes in the codebase and PRs that move toward filtering and matching by subscription ID and reference ID, not just by customer ID alone ([example](https://github.com/better-auth/better-auth/pull/3622)). If you make this change, review related endpoints (like cancellation and restoration) to ensure they're also referenceId- and subscriptionId-aware, but there are no deep blockers in the Stripe integration itself—it's an application-layer restriction. The modular structure means you can localize your changes to the relevant subscription management functions ([source](https://github.com/better-auth/better-auth/blob/c7a272f26137bb1eeafae267d460fc105f4ad714/packages/stripe/src/index.ts)). There’s no official documentation for this yet, so thorough testing is recommended if you relax this restriction. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/cf1d5da5-a043-4ce5-a340-fe384d2aca24?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/cf1d5da5-a043-4ce5-a340-fe384d2aca24?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/cf1d5da5-a043-4ce5-a340-fe384d2aca24?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/cf1d5da5-a043-4ce5-a340-fe384d2aca24?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/cf1d5da5-a043-4ce5-a340-fe384d2aca24?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/cf1d5da5-a043-4ce5-a340-fe384d2aca24?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/cf1d5da5-a043-4ce5-a340-fe384d2aca24?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/3979)
Author
Owner

@aniravi24 commented on GitHub (Aug 13, 2025):

I patched that section with this snippet which appears to work, do you think this makes sense? @dosu

        const activeSubscription = subscriptionToUpdate ? activeSubscriptions.find(
          (sub) => sub.id === subscriptionToUpdate.stripeSubscriptionId
        ) : existingSubscription ? activeSubscriptions.find(
          (sub) => sub.id === existingSubscription.stripeSubscriptionId
        ) : null;
<!-- gh-comment-id:3184990343 --> @aniravi24 commented on GitHub (Aug 13, 2025): I patched that section with this snippet which appears to work, do you think this makes sense? @dosu ``` const activeSubscription = subscriptionToUpdate ? activeSubscriptions.find( (sub) => sub.id === subscriptionToUpdate.stripeSubscriptionId ) : existingSubscription ? activeSubscriptions.find( (sub) => sub.id === existingSubscription.stripeSubscriptionId ) : null; ```
Author
Owner

@dosubot[bot] commented on GitHub (Aug 13, 2025):

Yes, your patch makes sense and aligns with the direction of recent changes in Better Auth's Stripe integration. By matching the active subscription specifically by subscriptionToUpdate.stripeSubscriptionId or existingSubscription.stripeSubscriptionId, you avoid the previous issue where any active subscription would trigger the upgrade flow, which blocked multiple concurrent subscriptions per user. This approach is consistent with how cancellation and restoration endpoints already work, and it matches recommendations from maintainers and recent PRs for multi-subscription support (example, discussion).

A couple of things to watch out for: there are known inconsistencies in the codebase between using subscription.id and subscription.stripeSubscriptionId, so make sure you use the correct identifier throughout your flows (reference). Also, if there are multiple active subscriptions and no ID is provided, it's best to throw an error or prompt for selection rather than defaulting to the first result to avoid silent mis-selection (reference).

Thoroughly test scenarios with multiple active/trialing subscriptions to catch any edge cases. If you update related endpoints (like cancellation, restoration, or webhooks), ensure they are also subscriptionId/referenceId-aware for consistency. There’s no official documentation for this yet, so your patch is a solid step toward robust multi-plan support.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3185002174 --> @dosubot[bot] commented on GitHub (Aug 13, 2025): <!-- Answer --> Yes, your patch makes sense and aligns with the direction of recent changes in Better Auth's Stripe integration. By matching the active subscription specifically by `subscriptionToUpdate.stripeSubscriptionId` or `existingSubscription.stripeSubscriptionId`, you avoid the previous issue where any active subscription would trigger the upgrade flow, which blocked multiple concurrent subscriptions per user. This approach is consistent with how cancellation and restoration endpoints already work, and it matches recommendations from maintainers and recent PRs for multi-subscription support ([example](https://github.com/better-auth/better-auth/pull/3622), [discussion](https://github.com/better-auth/better-auth/issues/3690)). A couple of things to watch out for: there are known inconsistencies in the codebase between using `subscription.id` and `subscription.stripeSubscriptionId`, so make sure you use the correct identifier throughout your flows ([reference](https://github.com/better-auth/better-auth/issues/2860)). Also, if there are multiple active subscriptions and no ID is provided, it's best to throw an error or prompt for selection rather than defaulting to the first result to avoid silent mis-selection ([reference](https://github.com/better-auth/better-auth/issues/3690)). Thoroughly test scenarios with multiple active/trialing subscriptions to catch any edge cases. If you update related endpoints (like cancellation, restoration, or webhooks), ensure they are also subscriptionId/referenceId-aware for consistency. There’s no official documentation for this yet, so your patch is a solid step toward robust multi-plan support. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/f87d1d1b-8423-4bd0-b8f6-37628a22234f?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/f87d1d1b-8423-4bd0-b8f6-37628a22234f?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/f87d1d1b-8423-4bd0-b8f6-37628a22234f?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/f87d1d1b-8423-4bd0-b8f6-37628a22234f?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/f87d1d1b-8423-4bd0-b8f6-37628a22234f?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/f87d1d1b-8423-4bd0-b8f6-37628a22234f?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/f87d1d1b-8423-4bd0-b8f6-37628a22234f?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/3979)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#9783