[GH-ISSUE #9089] Stripe checkout URL for upgradeSubscription broken when user manages subscriptions for multiple organizations #19900

Closed
opened 2026-04-15 19:15:47 -05:00 by GiteaMirror · 9 comments
Owner

Originally created by @mortenson on GitHub (Apr 10, 2026).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/9089

Originally assigned to: @bytaesu on GitHub.

Is this suited for github?

  • Yes, this is suited for github

Reproduction

  1. Install the stripe plugin
  2. Configure it minimally to support organization customers and subscriptions:
stripe({
  // Prevent user customers from being created
  createCustomerOnSignUp: false, 
  organization: {
    enabled: true,
  },
  subscription: {
    enabled: true,
      plans: [...] // Replace with valid plan configuration
  }),
  stripeWebhookSecret: WEBHOOK_SECRET,
  stripeClient: stripeClient,
})
  1. Create an organization (Org A) and sign up with a subscription for it.
  2. Create another organization (Org B) and sign up with a subscription for it.
  3. Call upgradeSubscription for Org B and visit the URL, see a message that says the user already has a subscription (I'm guessing for Org A) and the checkout flow is generally broken:
Image
  1. Call upgradeSubscription for Org A and visit the URL, see that the checkout flow is normal.
  2. Call createBillingPortal for Org A and visit the URL. See that the content on the page is normal and associated with Org A.
  3. Call createBillingPortal for Org B and see that the content on the page is associated with Org A.

Current vs. Expected behavior

Current: upgradeSubscription seems slightly wonky when using multiple organizations. I'm guessing the Stripe checkout session is not being created properly for some reason.

Expected: Users can call upgradeSubscription with references to any organization they have access to and have the URL work properly.

What version of Better Auth are you using?

1.5.4

System info

{
  "system": {
    "platform": "linux",
    "arch": "x64",
    "version": "#1 SMP PREEMPT_DYNAMIC Thu Jun  5 18:30:46 UTC 2025",
    "release": "6.6.87.2-microsoft-standard-WSL2",
    "cpuCount": 12,
    "cpuModel": "AMD Ryzen 5 3600 6-Core Processor",
    "totalMemory": "7.76 GB",
    "freeMemory": "3.57 GB"
  },
  "node": {
    "version": "v24.3.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "11.4.2"
  },
  "frameworks": [
    {
      "name": "express",
      "version": "^5.1.0"
    }
  ],
  "databases": [
    {
      "name": "pg",
      "version": "^8.16.3"
    },
    {
      "name": "drizzle",
      "version": "^0.44.7"
    }
  ],
  "betterAuth": {
    "version": "Unknown",
    "config": null,
    "error": "Converting circular structure to JSON\n    --> starting at object with constructor 'Stripe'\n    |     property 'account' -> object with constructor 'Constructor'\n    --- property '_stripe' closes the circle"
  }
}

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

Backend

Auth config (if applicable)


Additional context

No response

Originally created by @mortenson on GitHub (Apr 10, 2026). Original GitHub issue: https://github.com/better-auth/better-auth/issues/9089 Originally assigned to: @bytaesu on GitHub. ### Is this suited for github? - [x] Yes, this is suited for github ### Reproduction 1. Install the stripe plugin 2. Configure it minimally to support organization customers and subscriptions: ```ts stripe({ // Prevent user customers from being created createCustomerOnSignUp: false, organization: { enabled: true, }, subscription: { enabled: true, plans: [...] // Replace with valid plan configuration }), stripeWebhookSecret: WEBHOOK_SECRET, stripeClient: stripeClient, }) ``` 3. Create an organization (Org A) and sign up with a subscription for it. 4. Create another organization (Org B) and sign up with a subscription for it. 5. Call `upgradeSubscription` for Org B and visit the URL, see a message that says the user already has a subscription (I'm guessing for Org A) and the checkout flow is generally broken: <img width="509" height="367" alt="Image" src="https://github.com/user-attachments/assets/53530438-3292-447a-bf08-2478387a3d41" /> 6. Call `upgradeSubscription` for Org A and visit the URL, see that the checkout flow is normal. 7. Call `createBillingPortal` for Org A and visit the URL. See that the content on the page is normal and associated with Org A. 8. Call `createBillingPortal` for Org B and see that the content on the page is associated with Org A. ### Current vs. Expected behavior Current: `upgradeSubscription` seems slightly wonky when using multiple organizations. I'm guessing the Stripe checkout session is not being created properly for some reason. Expected: Users can call `upgradeSubscription` with references to any organization they have access to and have the URL work properly. ### What version of Better Auth are you using? 1.5.4 ### System info ```bash { "system": { "platform": "linux", "arch": "x64", "version": "#1 SMP PREEMPT_DYNAMIC Thu Jun 5 18:30:46 UTC 2025", "release": "6.6.87.2-microsoft-standard-WSL2", "cpuCount": 12, "cpuModel": "AMD Ryzen 5 3600 6-Core Processor", "totalMemory": "7.76 GB", "freeMemory": "3.57 GB" }, "node": { "version": "v24.3.0", "env": "development" }, "packageManager": { "name": "npm", "version": "11.4.2" }, "frameworks": [ { "name": "express", "version": "^5.1.0" } ], "databases": [ { "name": "pg", "version": "^8.16.3" }, { "name": "drizzle", "version": "^0.44.7" } ], "betterAuth": { "version": "Unknown", "config": null, "error": "Converting circular structure to JSON\n --> starting at object with constructor 'Stripe'\n | property 'account' -> object with constructor 'Constructor'\n --- property '_stripe' closes the circle" } } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript ``` ### Additional context _No response_
GiteaMirror added the needs: infopayments labels 2026-04-15 19:15:47 -05:00
Author
Owner

@bytaesu commented on GitHub (Apr 10, 2026):

Note

https://better-auth.com/docs/plugins/stripe#creating-organization-subscriptions

Could you confirm that customerType is being passed as org? This is needed because there may be use cases where both org and user subscriptions coexist.

<!-- gh-comment-id:4219676601 --> @bytaesu commented on GitHub (Apr 10, 2026): > [!NOTE] > https://better-auth.com/docs/plugins/stripe#creating-organization-subscriptions Could you confirm that customerType is being passed as org? This is needed because there may be use cases where both org and user subscriptions coexist.
Author
Owner

@mortenson commented on GitHub (Apr 10, 2026):

@bytaesu Yes, confirmed. I was in some time pressure so I ended up removing the stripe plugin and using https://docs.stripe.com/customer-management/portal-deep-links manually myself, which worked for users who were owners of multiple organizations.

<!-- gh-comment-id:4220974799 --> @mortenson commented on GitHub (Apr 10, 2026): @bytaesu Yes, confirmed. I was in some time pressure so I ended up removing the stripe plugin and using https://docs.stripe.com/customer-management/portal-deep-links manually myself, which worked for users who were owners of multiple organizations.
Author
Owner

@bytaesu commented on GitHub (Apr 10, 2026):

@mortenson

In our Stripe plugin, organization customers are created without an email per-fill. (org itself doesn't have email)

Your screenshot shows myorg+foo@example.com pre-filled, which indicates that a user-type customer was used for this Checkout session.

Could you check the customerType field in the Stripe customer metadata from your Dashboard?

<!-- gh-comment-id:4221204655 --> @bytaesu commented on GitHub (Apr 10, 2026): @mortenson In our Stripe plugin, organization customers are created without an email per-fill. (org itself doesn't have email) Your screenshot shows `myorg+foo@example.com` pre-filled, which indicates that a user-type customer was used for this Checkout session. Could you check the `customerType` field in the Stripe customer metadata from your Dashboard?
Author
Owner

@mortenson commented on GitHub (Apr 10, 2026):

@bytaesu Confirmed, it's an organization customer type. I was creating the customer like this in a hook:

      const resp = await stripeClient.config.stripe.customers.create({
        email: email,
        name: organization.name,
        metadata: {
          customerType: "organization",
          organizationId: organization.id,
        },
      });
Image
<!-- gh-comment-id:4221273009 --> @mortenson commented on GitHub (Apr 10, 2026): @bytaesu Confirmed, it's an organization customer type. I was creating the customer like this in a hook: ```ts const resp = await stripeClient.config.stripe.customers.create({ email: email, name: organization.name, metadata: { customerType: "organization", organizationId: organization.id, }, }); ``` <img width="326" height="193" alt="Image" src="https://github.com/user-attachments/assets/3ce26c8a-9bd3-4661-aef7-45dc79a10334" />
Author
Owner

@bytaesu commented on GitHub (Apr 10, 2026):

You can use getCustomerCreateParams
https://better-auth.com/docs/plugins/stripe#customer-management

If you create the customer manually, it bypasses our plugin logic, which makes it difficult for me to check.

<!-- gh-comment-id:4221418251 --> @bytaesu commented on GitHub (Apr 10, 2026): You can use `getCustomerCreateParams` https://better-auth.com/docs/plugins/stripe#customer-management If you create the customer manually, it bypasses our plugin logic, which makes it difficult for me to check.
Author
Owner

@bytaesu commented on GitHub (Apr 10, 2026):

@mortenson Is there a reason you're creating the org customer manually? We already handle that part internally.

<!-- gh-comment-id:4221431574 --> @bytaesu commented on GitHub (Apr 10, 2026): @mortenson Is there a reason you're creating the org customer manually? We already handle that part internally.
Author
Owner

@mortenson commented on GitHub (Apr 10, 2026):

@bytaesu IIRC better auth doesn't have a way to create organization customers automatically (on creation) like with users

<!-- gh-comment-id:4221619126 --> @mortenson commented on GitHub (Apr 10, 2026): @bytaesu IIRC better auth doesn't have a way to create organization customers automatically (on creation) like with users
Author
Owner

@bytaesu commented on GitHub (Apr 10, 2026):

@bytaesu IIRC better auth doesn't have a way to create organization customers automatically (on creation) like with users

Image
<!-- gh-comment-id:4221653132 --> @bytaesu commented on GitHub (Apr 10, 2026): > [@bytaesu](https://github.com/bytaesu) IIRC better auth doesn't have a way to create organization customers automatically (on creation) like with users <img width="912" height="329" alt="Image" src="https://github.com/user-attachments/assets/f3a214a5-24eb-4715-8423-7bee89b11909" />
Author
Owner

@bytaesu commented on GitHub (Apr 10, 2026):

I'm closing this issue. If you have further questions, feel free to let me know 😁

<!-- gh-comment-id:4223694720 --> @bytaesu commented on GitHub (Apr 10, 2026): I'm closing this issue. If you have further questions, feel free to let me know 😁
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#19900