Stripe has recently launched Radar 2.0 to improve payment fraud detection. One of the requirements for using Radar 2.0 is that you need to provide the cardholder name during the purchase.
I'm using the "custom" form of Stripe's checkout.js documented here.
The documentation does not tell you how to specify the cardholder name as part of the checkout process. Has anyone figured this out?
I've copied relevant portions of my implementation below in case that is helpful.
If this can't be done, then I guess Stripe is insisting that people upgrade to Stripe Elements, but if that is that case it would be great for them to say so.
<script src="https://checkout.stripe.com/checkout.js"></script>
$(document).ready(function() {
var stripe_btn = document.getElementById('stripe-btn');
var handler = StripeCheckout.configure({
key: 'pk_live_...',
token: function(token) {
$("#stripe-token").val(token.id);
$("#stripe-form").submit();
}
});
stripe_btn.addEventListener('click', function(e) {
// Open Checkout with further options:
handler.open({
email: $('#stripe-btn').data('email')
});
e.preventDefault();
});
// Close Checkout on page navigation:
window.addEventListener('popstate', function() {
handler.close();
});
});
Stripe Checkout does not support collecting only the cardholder's name today. There's also no way to pre-fill or pass the cardholder's name to Checkout if you already have it on your end.
The only solution in that case would be to collect the full billing address instead which would also collect the cardholder's name. This can be done by passing billingAddress: true to the StripeCheckout.configure() call.
Related
I'm creating reusable SEPA source by first creating a client_secret server-side:
await stripe.setupIntents.create({
payment_method_types: ["sepa_debit"],
customer: "..."
});
I then pass the client_secret to <Elements /> as an option:
<Elements
stripe={...}
options={{
locale,
clientSecret: setupIntentClientSecret,
...
}}
>
Once the customer enters their SEPA debit data, I confirm the setup client-side via:
await stripe.confirmSetup({
elements,
confirmParams: {
return_url: window.location.href
},
redirect: "if_required"
})
Now, the SEPA debit best practices mention that
Source objects provide tooling to help you notify your users compliantly. At Source creation it is possible to specify a mandate[notification_method].
So how can I specify this mandate attribute client-side? I suppose it simply isn't possible and I'll need to update the newly created source server-side?
EDIT:
Source updating won't work because the object created by calling stripe.confirmSetup is a payment_method, not a source 🤔
The documentation you've shared (link) is for the older SEPA integration path using the Sources API. Instead, you should refer to this guide which references mandate collection and uses the new APIs including Setup Intents, Payment Methods and the Payment Element (as per the code you've shared).
The stripe documentation says when using payment intent using automatic confirmation you should Asynchronously fulfill the customer’s order using webhooks.
If i'm offering a service e.g. ability to download a file once purchased then why do I need to monitor for the payment_intent.succeeded webhook?
If payment succeeded in the following handleCardPayment function then is there still a possibility for the charge to fail? Why shouldn't I allow the user to download the file straight away if the payment has succeeded?
var cardholderName = document.getElementById('cardholder-name');
var cardButton = document.getElementById('card-button');
var clientSecret = cardButton.dataset.secret;
cardButton.addEventListener('click', function(ev) {
stripe.handleCardPayment(
clientSecret, cardElement, {
payment_method_data: {
billing_details: {name: cardholderName.value}
}
}
).then(function(result) {
if (result.error) {
// Display error.message in your UI.
} else {
// The payment has succeeded. Display a success message.
}
});
});
Maybe I've not understood how the handleCardPayment works. Any help appreciated.
When using handleCardPayment, the issue is not so much that the payment might fail, it's that it might succeed but your code doesn't know about it.
handleCardPayment kicks off several asynchronous steps — showing the user a dialog to authenticate a payment with their bank, processing the actual charge against their card, and closing the dialog. It's only after all that completes does the Promise resolve and your function that receives result executes.
Consider the case where:
the customer clicks Pay
handleCardPayment is called
the customer sees a dialog from their bank to authenticate the
payment
they do that, and they consider that their payment is now complete,
and they close their browser immediately.
In this case, your code will never execute, but Stripe still processed the charge. So you don't know that the payment happened and you can't fulfil the order.
That's why it's important to use webhooks, so you get notified asynchronously when the payment completed, even if the user closed their browser mid-process and your code after handleCardPayment never got a chance to run. Alternatively you can use the manual confirmation flow, where the steps are split up and the actual charge isn't processed until your server makes a separate API call.
I am trying to implement a secure payment option with react-paypal-express-checkout...
but I saw that user can easily change the amount with chrome dev tools ... shouldn't I make the API request to paypal from my server and validate the amount with my DB? I didn't saw any option to do that with paypal...
here is my code:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import 'react-credit-cards/es/styles-compiled.css'
import './checkout.css';
import PaypalExpressBtn from 'react-paypal-express-checkout';
class CheckOut extends Component {
constructor(props) {
super(props);
this.state = {
amount: 40
}
}
render() {
const client = {
sandbox: 'XXXX',
production: 'Your-Production-Client-ID',
}
return (
<PaypalExpressBtn client={client} currency={'USD'} total={this.state.amount} />
);
}
}
export default connect(CheckOut);
Paypal allows both types of uses, from the client and from the server. I guess it's possible for the client to modify the request on their end to pay less. But, in the end, whatever your business is, you'll get an order and a payment. Just check if the payment is different than it should be and don't fulfil the order, make a refund.
If you want to save the trouble, then use the server option that makes the payment through your server.
In any case, like with any other payment method, I would recommend you take the time to implement it yourself following the great and well documented API provided by Paypal. They have a lot of examples and use cases, with code for the browser and the server.
Never trust values coming from the client side. You should absolutely validate the amount on the server-side.
As #jorbuedo said, you can create a server integration so the values are never exposed client side. Send a session ID or Order Number or something to your server, retrieve the order from your DB, and perform a redirect to PayPal to process the transaction server-side.
Alternatively, you can keep the client-side stuff you have, but then validate the transaction after it's been complete. You could use Instant Payment Notifications or the newer Webhooks to do this.
You could pass a custom variable into the paymentOptions property of <PaypalExpressButton ...>, and then use this value to validate the correct amount has been paid in IPN.
For example:
<PaypalExpressButton
client={client}
currency="USD"
total={this.state.amount}
paymentOptions={{
custom: this.props.sessionId
}}
/>
Then, as part of IPN, you can pull the Session ID out the DB, check the expected payment amount (which you'll need to store, or calculate based on the items/prices saved against the session ID) is the same as the payment amount Paypal provides (mc_gross for example). A full list of variables you get as part of IPN is available here.
There are no fees for using IPN. If you didn't want to build out this flow, then you'd have to manually validate every order that's made to ensure the amount is correct. If you're running something small, this might be an acceptable compromise.
Edit: Don't just send the expected amount as the Custom variable, and compare that to the mc_gross value, as this can also be changed using F12 or a browser extension. The value needs to be something opaque that you can translate server-side into something meaningful.
#jorbuedo and #Dave Salomon give great answers about Security and you should take them in to consideration.
However, If you really don't want to user to change your Component state and props, You can disable React Devtools with this hack.
if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.emit = function() {};
}
Basically it mocks some methods of react-devtools and Devtool cannot find your component tree anyway.
This answer is only for disabling user to edit your components. This is not best solution for security)
I'm using Create PayPal SDK to make a transaction using paypal and redirecting the user to paypal.
I'm using the same code as per suggested in above link, but i want to send invoice number with create paypal to be shown under transaction detail. but i am not able to find how can i send a invoice number to paypal.
Please guide me if there is any object in which i can sent the invoice number to Create PayPal SDK OR any other method through which i can sent invoice number to PayPal.
Note: this project is in sailsjs.
Thanks
Please check this: https://github.com/paypal/PayPal-node-SDK/blob/master/samples/invoice/send.js
var invoiceId = "INV2-GLJ8-9FA2-26BB-GHLU";
paypal.invoice.send(invoiceId, function (error, rv) {
if (error) {
console.log(error.response);
throw error;
} else {
console.log("Send Invoice Response");
console.log(rv);
}
});
Please look at the complete invoice example here, there is everything you need: https://github.com/paypal/PayPal-node-SDK/tree/master/samples/invoice
As per documentation you can handle your custom IDs:
For exploring additional payment capabilites, such as handling
discounts, insurance, soft_descriptor and invoice_number, have a look
at this example. These bring REST payment functionality closer to
parity with older Merchant APIs. https://github.com/paypal/PayPal-node-SDK
Checkout from Stripe has a great way to add a credit card for a transaction, by simply invoking StripeCheckout.open().
Is it possible to use .open() to edit a card? (passing in the card token)
Also, where can I download a non-minified version of checkout.js to see the .open() method signature?
There is no way to edit a card that way. What you can do though is use Stripe Checkout to ask your customer for a new card without asking him to pay anything. The idea is to avoid setting the amount or data-amount parameter.
<form action="/charge" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="pk_test_XXX"
data-name="Demo Site"
data-description="Update Card Details"
data-panel-label="Update Card Details"
data-label="Update Card Details">
</script>
</form>
You would get a new card token for that new card and you could then use the Update Customer API to save the new card on the customer.
As for your second question, there is unfortunately no unminified version of Checkout.js accessible at the moment.
Try http://unminify.com/ to see an unminified version of checkout.
I saw this done for the first time today. If you have an app where users log in, you should be able to do it with a custom Checkout integration (the above is the simple integration) found here https://stripe.com/docs/checkout#integration-custom
On the server side you would retrieve the customer via Stripe's API. From the linked custom example, you can pass the retrieved ID through to Checkout via session data so it knows which customer to update here:
$('#customButton').on('click', function(e) {
// Open Checkout with further options
handler.open({
name: 'Your Company Name',
email: customer_email,
id: customer_id,
zipCode: false,
});
I have not yet tested this, if I get a chance I'll report back.