Skip to content

Instantly share code, notes, and snippets.

@d1manson
Last active August 31, 2021 17:22
Show Gist options
  • Save d1manson/7ac82e100add42e747dcbea72c1100cd to your computer and use it in GitHub Desktop.
Save d1manson/7ac82e100add42e747dcbea72c1100cd to your computer and use it in GitHub Desktop.
for use in testing stripe intents server side. note this is for use with a test mode key. relies on implementation details that might change
const { STRIPE_PUBLIC_KEY } = process.env,
axios = require("axios"),
qs = require("querystring").stringify,
{ JSDOM } = require("jsdom");
module.exports.simulateAction = async function(
intentId,
clientSecret,
mode = "setup_intent"
) {
// These are all the bits we have to gather as we go along
const data = {
url1: null,
url2: null,
url3: null,
url4: null
};
if (mode === "setup_intent") {
data.url1 = `https://api.stripe.com/v1/setup_intents/${intentId}`;
} else {
data.url1 = `https://api.stripe.com/v1/payment_intents/${intentId}`;
}
try {
const res1 = await axios({
url: data.url1,
method: "GET",
params: {
is_stripe_sdk: false,
key: STRIPE_PUBLIC_KEY,
client_secret: clientSecret
}
});
data.url2 = res1.data.next_action.use_stripe_sdk.stripe_js;
const res2 = await axios({
url: data.url2
});
const doc2 = new JSDOM(res2.data);
data.url3 = doc2.window.document.querySelector(`input[name='return_url']`).value;
const res3 = await axios({
url: data.url3,
method: "POST"
});
const doc3 = new JSDOM(res3.data);
data.url4 = doc3.window.document.querySelector("form").action;
await axios({
url: data.url4,
method: "POST",
data: qs({ PaRes: "success" })
});
} catch (err) {
console.dir(err);
throw new Error("simulateAction failed");
}
};
@d1manson
Copy link
Author

d1manson commented Jan 18, 2021

Annoyingly Stripe don't provide a way to simulate a user doing the "requires action" step in 3DSecure - the only option is to follow the flow in the browser as though an actual user was doing it.

Here, we do follow the flow, but in the style of scraping rather than being a proper (headless or otherwise) browser.

If this stops working, it's worth checking if Stripe have updated their api to offer an easy way to do this. You could also check if anyone else has published another utility that does this.

If you do decide you have to get your hands dirty and fix it, it may not be that hard. The main thing is to run through the flow in Chrome with the network tab open. and look for all the "interesting" requests to stripe's domain. Use Chrome's copy as curl thing on the right-click menu of the relevant requests.

To get comparable curl requests from this code you can run:

npm i axios-curlirize

And then after requiring axios in the code, do:

 require("axios-curlirize")(axios);

I ended up using Chrome with incognito mode - I'm not sure if it made a difference, but it seems that there weren't any relevant cookies. In fact I didn't find any relevant headers at all in the end.

The main thing is to be very precise when comparing the curl requests in chrome and the curl requests from axios here, otherwise you will end up going around in circles!

@d1manson
Copy link
Author

This broke in late Aug 2021, had to remove a bit of the logic for going from step 3 to 4. should work again

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment