this post was submitted on 06 Apr 2025
4 points (62.5% liked)

Security

5411 readers
3 users here now

Confidentiality Integrity Availability

founded 5 years ago
MODERATORS
 

Why does Stripe require OAuth tokens to pass through a third party server?

Can someone who understands OAuth better than me explain to me why Stripe REQUIRES that their OAuth Access Keys get shared with a third party?

I've tried RTFM, but my biggest hangup is that the OAuth docs appear describe a very different situation than mine. They usually describe a user agent (web browser) as the client. And they talk about "your users" as if I have a bunch of users that I'm going to be fetching access keys for.

Nah, this is server <--> server. I have a server. Stripe has a server. I am one user. All I need is ONE API key for ONE account. But I'm forced to use OAuth. It doesn't seem appropriate, and it's especially concerning that the "flow" requires the (non-expiring!) Access Token to be shared with a third party server. Why?!?

I recently learned that Stripe has been pushing OAuth (branded as "Stripe Connect") to its integration apps as the "more secure" solution, compared to Restricted API Keys. In fact, we've found that most integrations we've encountered that use Stripe Connect are less secure than using Restricted API Keys because the (private!) tokens are shared with a third party!

I've been using Stripe to handle credit card payments on my e-commerce website for years. Recently, we updated our wordpress e-commerce website and all its plugins. And then we discovered that all credit card payments were broken because our Stripe Payment Gateway plugin stopped allowing use of Restricted API Keys. Instead they only support "Stripe Connect" (which, afaict, is a marketing term for OAuth). This change forced us to do a security audit to make sure that the new authentication method met our org's security requirements. What we found was shocking.

So far we've started auditing two woocommerce plugins for Stripe, and both have admitted that the OAuth tokens are shared with their (the developer's) servers!

One of them is a "Stripe Verified Partner", and they told us that they're contractually obligated by Stripe to use only "Stripe Connect" (OAuth) -- they are not allowed to use good-'ol API Keys.

They also told us that Stripe REQUIRED them to include them in the OAuth flow, such that their servers are given our (very secret!) OAuth Access Keys!

The benefit of normal API Keys, of course, is that they're more secure than this OAuth setup for (at least) two reasons:

  1. I generate the API keys myself, and I can restrict the scope of the keys permissions

  2. I store the key myself on my own server. It's never transmitted-to nor stored-on any third party servers. Only my server and Stripe's servers ever see it.

Can someone shine a light onto this darkpattern? I understand that standardization is good. OAuth Refresh Keys add security (this service doesn't use them). But why-oh-why would you FORCE OAuth flows that share the (non-expiring) Access Tokens with a third party? And why would you claim that's more secure than good-ol-API-keys?

Does OAuth somehow not support server<-->server flows? Or is it a library issue?

What am I missing?

top 7 comments
sorted by: hot top controversial new old
[–] [email protected] -1 points 1 week ago (3 children)

I do not want to discredit your post in any form. Just was curious and needed to ask someone with more code on the Internet than me, so I UTFAI (used the fricking AI). And while I can't confirm any of its output, it does have an interesting spin on it. (Which is probably mostly wrong, heavily colored by the input and stolen anyway) ---- Ai Output ----> You’re not missing much — in fact, you’ve identified a very legitimate concern, and your analysis is spot on. This whole situation boils down to how Stripe Connect is being (mis)used, how OAuth is being (mis)applied, and how plugin developers are monetizing integration at the cost of your security. Let’s break this down in detail:


  1. Stripe Connect vs. Traditional API Keys

Stripe Connect is not just OAuth. It’s an entire product meant to support multi-party platforms like marketplaces (e.g., Uber, Etsy). Stripe Connect allows a platform to onboard “connected accounts” and take actions on their behalf — that’s what the OAuth flow is for.

If you're building a platform that enables others to get paid (e.g., vendors or gig workers), OAuth makes sense: you redirect them to Stripe, they grant access, and your platform can charge on their behalf, take a cut, etc.

But you’re not a platform. You’re a merchant. A single user. You just want your own server to talk to Stripe's API securely. In this case, the OAuth flow is overkill and often less secure, especially if it involves third parties.


  1. Why Plugins Use Stripe Connect and a Proxy Server

There’s one simple reason plugin developers are doing this:

To insert themselves into the flow and monetize the connection.

By forcing an OAuth flow:

They can act as a "platform" in Stripe's eyes, and you become a “connected account.”

They gain access to your non-expiring access tokens — meaning, they can charge customers, issue refunds, or read your payment data.

They may host part of the OAuth flow on their server to log/store your token (which should never leave your control).

They often call this a “simpler setup” or “easier onboarding,” but really it gives them persistent access to your Stripe account.

This isn’t an inherent flaw in OAuth the protocol — this is OAuth being used deceptively, with Stripe's apparent blessing, to enable middleman business models.


  1. Why Stripe Is Pushing This

Here’s where it gets cynical:

Stripe makes more money from Stripe Connect integrations because they enable platform-style business models — which might mean higher volume, or fees being taken by multiple parties.

Stripe also standardizes how integrations work, and Connect allows them to say, "all platforms follow the same flow" — easier to support, easier to sell, easier to track.

By requiring all plugins to use Connect, they gain:

Better monitoring

Cleaner onboarding UX

Centralized partner management

Unfortunately, security and privacy for the end-user merchant can take a back seat.


  1. Why This Is Less Secure Than API Keys

You nailed it already, but to reiterate:

With API keys: you generate them, you scope them, and you store them. No third parties involved.

With this OAuth flow: the access token is created and passed through a third party (e.g., plugin dev’s server), and you don’t always know what they’re doing with it — logging, storing, or abusing.

Also, many plugins don’t even use refresh tokens, meaning the access token is non-expiring — that's essentially a password that lives forever in someone else’s database.


  1. Does OAuth Support Server-to-Server?

Yes, absolutely. It’s called the Client Credentials flow (RFC 6749, Section 4.4). But:

Stripe Connect does not support Client Credentials flow.

Stripe Connect is meant for third-party delegation, not internal server-to-server access.

Your use case is better suited to API keys or an internal OAuth setup, not this Connect model.

So yes, OAuth can support proper server-to-server comms, but that’s not what Stripe Connect is doing here.


  1. What Can You Do?

Roll your own integration using Stripe’s SDK and a Restricted API key. You’ll lose plugin convenience, but gain security and control.

Find a plugin that doesn’t require Stripe Connect. Harder now, since Stripe and WP plugin devs are moving away from API keys.

Raise the issue with Stripe. If enough merchants push back on the mandatory use of Connect, they may re-enable support for restricted keys.

Audit and monitor token use: if you're stuck using a plugin, ensure the access token is restricted, and rotate it if possible.


TL;DR

You're absolutely right to be concerned. OAuth isn't the issue — it's the way it's being forced via Stripe Connect, often unnecessarily and insecurely. Stripe has shifted from empowering merchants with direct control to funneling them through "platforms" (aka plugin vendors) that often require sharing sensitive tokens. That’s not more secure — it’s just more profitable for Stripe and the plugin devs.

Let me know if you want help writing a secure custom integration with Stripe using only API keys — happy to help avoid this nonsense.

[–] [email protected] 1 points 1 week ago* (last edited 1 week ago)

It’s called the Client Credentials flow (RFC 6749, Section 4.4).

Finally someone directs me to the actual RFC. Except that section is titled "Client Credentials Grant"

Why do I see this sometimes called a "Grant" and sometimes called a "Flow"?

What's the definition and difference of each?

[–] [email protected] 1 points 1 week ago (1 children)

I figured out the root technical cause. It's because Stripe doesn't allow the redirect during the OAuth flow to be dynamic. It must be a predefined value that's hard-coded into the app.

For security purposes, Stripe redirects a user only to a predefined URI.

That's why Stripe forces you to expose your access tokens to the developer's servers.

I'd still appreciate if someone with more experience with OAuth than me knows if this is common. Seems like a very bad design decision to require users to transmit their bearer tokens through the developer's servers.

[–] [email protected] 1 points 1 week ago* (last edited 1 week ago) (1 children)

I do believe keycloak does the same. In keyCloak one would create a client application service. Here one will provide valid redirect URIs. For example a user wants to login with SSO, provides their credentials and the key cloak service returns the token. Than the user will be redirected to the valid redirection target. The frontend, which will send the token to an backend, this backend is able to verify the token either by itself or through another connection to the keycloak service.

[–] [email protected] 1 points 1 week ago (1 children)

That's bad.

OAuth supports several types of flows. If I'm not mistaken (I've learned a bit more about OAuth since yesterday) you're describing the Authorization Code Flow -- as documented in RFC 6749 (The OAuth 2.0 Authorization Framework), Section 4.1 (Authorization Code Grant):

That RFC defines many other types of flows that do not require sharing the access keys with a third party, such as the Client Credentials Flow, as documented in RFC 6749 Section 4.4 (Client Credentials Grant):

The only reason you'd want to use the Authorization Code Flow is if the third party needs your access token for some reason, or if you want to hide the access key from the user agent.

The problem here is that Stripe is using the wrong flow (the third party doesn't need the access token, as they claim they never save it anyway). And if keyCloak only supports that one flow, that's would be a problem too (in this case).

[–] [email protected] 2 points 1 week ago

I see. If memory serves me well, key cloak does have different flows, but we never used those, since we had no need.

So yeah, that's bad.

[–] [email protected] 1 points 1 week ago

Stripe Connect does not support Client Credentials flow.

Can you please tell me what is the name of the "flow" that Stripe Connect is using here?