Specifying mandate[notification_method] client-side with Stripe.js? - stripe-payments

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).

Related

How can I allow users to join Google Meet without having to ask?

I'm scheduling a google meet based on specific time and date, and so far it's going well, it generates a google meet link. But the only problem is that I have to ask to join while no one is there to accept. Is there is a way to get around this? knowing that I get the emails of both of the participants.
I'm using a package called google-meet-api
This is the code:
const meetingLink = await Meeting({
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
refreshToken: process.env.REFRESH_TOKEN,
date,
time,
summary: 'Interview',
location: 'Online',
description: 'Interview',
});
if (!meetingLink) {
throw new CustomError('Error creating the meeting, please try again later', 500);
}
console.log(meetingLink) // https://meet.google.com/arr-yrre-t**
If you're the primary user or one of the invitees, then the URL should give you the option to "join the meeting" even if noone else (including the organizer) is present.
Without more details in your question, it's difficult to provide more help.
Are you using this NPM package: google-meet-api?
The NPM package is an implementation of the Google SDK method and is little more than the example code that's provided by Google.
I encourage you to consider writing this code for yourself and saving yourself a mostly redundant depdendency on a 3rd-party NPM package that adds very little value.
The Google documentation page for the calendar Events:insert method (which is what is being used by the google-meet-api package) provides details of the parameters and the request body.
By reviewing the parameters and request body fields, you can confirm to yourself whether you're missing one of the fields that would address your problem.

Secure payment with paypal

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)

Add cardholder name with Stripe custom checkout

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.

Stripe recurring payments for 3DS source

I want to use Stripe to charge cards recurrently every 30 days with amounts that oscilate.
From the docs I got that if there is a possibility that the card requires 3DS we should use Sources so I switched to sources ;)
From the source object stripe.js retrieves I look at three_d_secure param to decide whether to create a source object that requires 3DS or a normal card charging.
The flow:
With JS I get the source object that has three_d_secure set to either optional or required.
When it's set to optional after I retrieve the source with: source = Stripe::Source.retrieve(source_id) it looks like this:
"status": "chargeable",
"type": "card",
"usage": "reusable",
"card":{"exp_month":12,"exp_year":2032,"brand":"Visa",...
I attach it to a customer and charge it. I guess usage: reusable means that I can charge the card again later...
When three_d_secure=='required' I create a new source calling this:
source = Stripe::Source.create({
amount: amount,
currency: currency,
type: 'three_d_secure',
three_d_secure: {
card: source_id, #src_xcvxcvxcvc
},
redirect: {
return_url: return_url
},
})
I redirect the user to the URL Stripe provides, user enters his 3DS PIN and gets back to my return_url. When Stripe redirects the user back to my return_url I retrieve the source again and get something like this:
"status": "chargeable",
"type": "three_d_secure",
"usage": "single_use",
"three_d_secure": {"card":"src_1B1JzQHopXUl9h9Iwk05JV1z","authenticated":true,"customer":null}
I would expect that after passing the 3DS the source becomes reusable and chargeable until the date of expiry or so :|
My questions are:
1 Why is the 3DS source single_use? Is this like this only in sanbox environment or with the card I am using to test?
2 Can a 3DS protected card be charged again at all?
3 What's the correct approach to attach to customer sources (3DS or normal) that can be charged again and again?
Thank you!
Because it is a source payment token, not a source card token. It expires on a due date or when is consumed. You can use reusable token to create single_use tokens. reusable one represents a card source token
Yes if a 3ds is optional or not_supported, no if required. If required then every payement needs to fulfill a 3ds.
Steps:
Create an src_card_token for a card or use saved one (reusable)
Create an customer object with an src from src_card_token
Create an src_payment_token for a customer using one of his saved cards (as token)
fullfil a 3ds redirect process if required.
create a charge

Edit a credit card using Stripe checkout.js

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.

Resources