Customize Stripe Checkout Form - javascript

I'm currently working on a stripe payment method inside my Angular application. By default, the stripe form has an 'email' input field of type 'email'. I wanted to change that input filed to 'Name' with the type 'text'. I've tried different methods but none really work Can somebody help me in this regard. Any help would very much appreciated. Thanks.
I'm Attaching a stripe form picture for further assistance.
MY Stripe method Implementation
loadStripe() {
console.log('loadStripe');
if (!window.document.getElementById('stripe-script')) {
let s = window.document.createElement('script');
s.id = 'stripe-script';
s.type = 'text/javascript';
s.src = 'https://checkout.stripe.com/checkout.js';
s.onload = () => {
console.log('token');
this.handler = (window as any).StripeCheckout.configure({
key: this.stripKey,
locale: 'auto',
token(token: any) {
// You can access the token ID with `token.id`.
// Get the token ID to your server-side code for use.
console.log('token', token);
alert('Payment Success!!');
}
});
};
window.document.body.appendChild(s);
}
}

Don't do this! Stripe Checkout is not supposed to be customized in this way and does not directly post data to your server but to Stripe's server. Whatever happens from when you bring up the Checkout panel to when they call you with a token is Stripe's web application, not yours, and may change at any time. If you try to change them, not only is your code prone to break from one day to another without warning, Stripe may detect it and think that the user's browser is running malware because you're not supposed to do that, and chances are attempting to change their UI is also a breach of contract.
If all you want to do is to pre-populate the email address with the one they've already written, you can pass it as the key email in the object passed to StripeCheckout.configure. But you're meant to collect all other information using your own form.
If you don't want to collect their email address and don't want Stripe Checkout to do so either, stop using Stripe Checkout and build your own form including credit card entry fields with Stripe Elements.

Related

Stripe checkout - Remove or make email field read only

I'm using stripe checkout as described in https://stripe.com/docs/payments/checkout
On the server side, I create a new stripe customer (if there isn't one already), and use that customer id to create a checkout session. and then redirect to checkout using stripe api
stripe.redirectToCheckout({
// Make the id field from the Checkout Session creation API response
// available to this file, so you can provide it as parameter here
// instead of the {{CHECKOUT_SESSION_ID}} placeholder.
sessionId: '{{CHECKOUT_SESSION_ID}}'
}).then(function (result) {
// If `redirectToCheckout` fails due to a browser or network
// error, display the localized error message to your customer
// using `result.error.message`.
});
in the checkout page (which is stripe hosted), there is a email field which is pre populated, but is editable. I have had customers changing that email address. Is there a way I can make the email address on stripe checkout readonly field?
A possible work around:
You can use customer_email instead customer parameter when you create a session.
In this case users can not change the value of email field.
Then, you can get the created customer and update it if you need added some data using the API: https://stripe.com/docs/api/customers/update
But, the problem is that stripe will create a new customer for each checkout.
I got an email from stripe today
We are disabling customers’ ability to overwrite their email address
Starting October 26, customers can no longer edit their email address after you pass it into a Checkout Session. We’ve made this change to prevent duplicative subscriptions from being created by accident for existing customers and prevent unexpected updates to the Customer object during Checkout.
And here it is in all its glory
Now, according to the Docs:
If the customer changes their email on the Checkout page, the Customer object will be updated with the new email.
Given that Stripe allows "customers" to change the email id. we pass to the Checkout form, an idea that could work for you is to add your "internal" identifier (be it an email or other internal user id) as Metatadata to the customer you create, like so (below code is in c#, but you get the idea):
Dictionary<string, string> customerMetaData = new Dictionary<string, string>();
customerMetaData.Add("myappuserid", "{useyourinternalidhere}");
var customer = await cs.CreateAsync(new CustomerCreateOptions { Email = "{emailthat youwanttouseforcustomer}", Metadata = customerMetaData });
//Now you can pass this customer when you create the session for checkout
The point being whatever email the user ends up using, you can always get the corresponding internal user id as well from the customer object's metadata.
In the "success" call back, you can then retrieve the customer data and then save the returned customer details - including the stripe customer id / email that end user used in check out form / your own internal id that you can now retrieve from the customer metadata -- that way you can maintain a mapping of stripe's details to your own internal customer details.
//This code is on the "success" call back (when the session id. is passed)
var sessionService = new SessionService();
var session = await sessionService.GetAsync(session_id, new SessionGetOptions { Expand = new List<string> { "customer" , "line_items", "subscription" } });
var sessionCustomer = session.Customer;
//This sessionCustomer now has the metadata that you passed while creating the customer
//Save the Stripe ids / email id along with data retrieved from the Metadata;
//Now you have all the info you required..
Of course this response is delayed - hopefully, it helps others...
Use "customer_email" parameter as shown below and this is the example in Python:
checkout_session = stripe.checkout.Session.create(
customer_email='example#gmail.com', # Here
line_items=[
{
'price_data': {
'currency': 'jpy',
'unit_amount': 1000,
'product_data': {
'name': 'Honey',
'description': 'Good honey',
},
},
'quantity': 1,
},
],
mode='payment',
success_url= "https://example.com/success.html",
cancel_url='https://example.com/cancel',
)
And because you use "customer_email" parameter so the email field is readonly as shown below:

How do I know that 3D Secure 2 authentication works after upgrading to stripe.js version 3

I have updated a site so it uses latest stripe-php (6.39.0) and it now loads stripe.js version 3. I’ve made all the necessary changes to my code so that my credit card fields are now displayed using Stripe Elements. Test transactions work and I have updated the live site and real payments are being excepted.
The reason I made this update was because I was informed by stripe that I needed to upgrade the site so that its stripe integration will work with Strong Customer Authentication (SCA) which is required in the EU by September 2019.
Stripe has different credit card test numbers you can use to test things that arise when processing payments. This numbers can be found here: https://stripe.com/docs/testing#cards
4000000000003220 simulates a transactions where 3D Secure 2 authentication must be completed. But when I use this code stripe turns down payment and returns the message:
"Your card was declined. This transaction requires authentication. Please check your card details and try again."
Does this mean that 3D Secure 2 is working or not?
In the real world it would open a window with an interface from the customer's card issuer. So I not sure wether my integration is working or not. As said before payments are being excepted butI need to ready when Strong Customer Authentication is required in September.
It seems you have an integration problem with the JS part. For a simple charge (the following example does not work for subscription), this is the way you have to implement it:
First you have to create a Payment intent (doc here: https://stripe.com/docs/api/payment_intents/create):
\Stripe\PaymentIntent::create([
"amount" => 2000,
"currency" => "usd",
"payment_method_types" => ["card"],
]);
Once your PaymentIntent response is returned, you will have a client_secret key (doc here : https://stripe.com/docs/api/payment_intents/object). You can see that your payment status is "requires_payment_method"
{
"id": "pi_1Dasb62eZvKYlo2CPsLtD0kn",
"object": "payment_intent",
"amount": 1000,
"amount_capturable": 0,
"amount_received": 0,
...
"client_secret": "pi_1Dasb62eZvKYlo2CPsLtD0kn_secret_6aR6iII8CYaFCrwygLBnJW8js",
...
"status": "requires_payment_method",
...
}
On your server side you have to save this object.
You can now show your payment form with the JS part with the previous client_secret key (doc here : https://stripe.com/docs/payments/payment-intents/verifying-status). The idea is that you have to call the Js function on click on the submit button but do not submit ! Wait for the response to submit.
With some jquery this should like this:
var $mySubmitButton = $('#my-submit-button'),
$myPaymentForm = $('#my-payment-form'),
clientSecret = $cardButton.data('client-secret'); // put your client-secret somewhere
$mySubmitButton.on('click', function(e) {
e.preventDefault();
// Disable button to disallow multiple click
$(this).attr("disabled", true);
stripe.handleCardPayment(
clientSecret,
{
payment_method: clientMethod, // if you have a clientMethod
}
).then(function(result) {
if (result.error) {
// show error message
// then enable button
$mySubmitButton.attr("disabled", false);
} else {
// Submit form
$myPaymentForm.submit();
}
});
});
If everything goes right, when you click your submit button, you will have a test 3D secure popin with the options to "success" or "fail" the security test. If you click on success button, your form is submitted and you have to wait for the webhook "charged.success" to confirm transaction.
Once received, change you server object status and notify user about the transaction.
In my case, once the form submitted, I show a loader and check with ajax call every second to see if my payment intent status have changed (through the webhook). For your test environnement, you can use http://requestbin.net and Postman.
Beware: some cards referenced on this page will not work properly (you can't add them) https://stripe.com/docs/testing#cards (section 3D Secure test card numbers and tokens). Confirmed with their support.
If you work with saved card, you can test only with these cards: https://stripe.com/docs/payments/cards/charging-saved-cards#testing

Generate recover email link in firebase

Is there any way to create custom recoverEmail link in firebase/firebase-admin?
I've checked the docs and tutorials there's none.
Any help would be great!
From my understanding there is currently no solution for this within the SDK. Instead, we took the approach of using admin.auth().generateSignInWithEmailLink(email, actionCodeSettings) and then replacing the mode within the returned link from signIn to recoverEmail.
const updatedLink = link.replace('signIn', 'recoverEmail');
This allowed us to customise the auth handler action as suggested here Create the email action handler page in the Firbase documentation.
Now we are able to call on admin.auth().updateUser again to reset the email to it's previous, along with update across our databases, merchant and other services. You'll also need to add the original email to a query in the updatedLink too.
const linkWithOriginalEmail = updatedLink.concat(`&email=${email}`)
Hope that helps and if anyone has a better solution we'd love to discuss.
I´m not sure if I understand your problem correctly, but If your goal is to have a custom link in the automatic email sent by Firebase when someone changes his authentication email address with updateEmail then you can define a custom action url in the Firebase console e.g. https://example.com/__/auth/action in the Authentication section and add the following code to the defined url (ref. https://firebase.google.com/docs/auth/custom-email-handler).
function handleRecoverEmail(auth, actionCode, lang) {
// Localize the UI to the selected language as determined by the lang
// parameter.
var restoredEmail = null;
// Confirm the action code is valid.
auth.checkActionCode(actionCode).then(function(info) {
// Get the restored email address.
restoredEmail = info['data']['email'];
// Revert to the old email.
return auth.applyActionCode(actionCode);
}).then(function() {
// Account email reverted to restoredEmail
// TODO: Display a confirmation message to the user.
// You might also want to give the user the option to reset their password
// in case the account was compromised:
auth.sendPasswordResetEmail(restoredEmail).then(function() {
// Password reset confirmation sent. Ask user to check their email.
}).catch(function(error) {
// Error encountered while sending password reset code.
});
}).catch(function(error) {
// Invalid code.
});
}

How to retrieve other users from a Firebase app?

I'm learning JavaScript and I'm trying to built a social app in a specific domain. Nothing big as usual social network because it's for a small community.
So I'm using Firebase, JavaScript ES6 and only one HTML file with an <app>. I already have and auth system, profile page for the current user. But my problem is that I don't know, understand the way to have pages from other's profile.
So as far as I succeed to go it's to get the other's users information from by Firebase database. But I'm stuck in my mind. Should I create an HTML file for each user? I don't think so?
This project is for a certification.
And my other problem is and can't make a verification from data. Well I succeed to check if data exist but it doesn't block the process so it updates anyway and get 2 users with the same name (see code below).
firebase
Atom
savePrenom(event){
let database = firebase.database();
event.preventDefault();
let uid = firebase.auth().currentUser.uid;
database.ref('users').once('value', (snapshot)=>{
snapshot.forEach( el=>{
if(prenom.value === el.val().prenom){
console.log('existe déjà');
}
if (prenom.value != el.val().prenom){
savePrenom.style.display= 'none';
editPrenom.style.display= 'block';
prenom.disabled = true;
database.ref('users/'+uid).update({
prenom: prenom.value
})
}
})
});
}
To solve your first problem: Do not create a html file for each user, that's terrible!
You should rather fetch the data and then use DOM manipulation to insert your data into the page. I do not know which database you are using so I can not give you a code sample for the fetching but only one for DOM manipulations.
Let's say you have the following html:
<p id='description'></p>
You can get the element by id and change it's properties, this is known as DOM manipulation.
document.getElementById('description').textValue = 'Very important'
This assigns Very important to the paragraph (the text will appear when executed by a browser).
Since you said you use plain ES6 only, I'm not going into backend technologies like NodeJS.
I can not help you with the second one since I lack information, please submit some code and tell us more about the technologies you are using.
Ok guys sorry for not responding for all question/answers but i got both solutions.
On the first one. As i could get the informations from a user a simply add some data-classes to passe the data that i could get from firebase. But their was a easier solution. From the moment i can get any information inside a user, i could get the key of each user using snapshot.key (which i forgot). So then it's easy, using a forEach element, each link to each profil use the right information on an other page.
Second question to check if a username already existe when changed for exemple. Well, i started to make a once reference value on my database users. Then if my pseudo.value === el.val().pseudo that means it existe to error message. If not, the user can change his username if wanted with .update for firebase.
database.ref('users').once('value', (snapshot)=>{
let find = false;
snapshot.forEach(el =>{
if(pseudo.value === el.val().pseudo){
//console.log('YEAH');
find = true
}
})
if (find === false) {
savePseudo.style.display= 'none';
editPseudo.style.display= 'block';
pseudo.disabled = true;
database.ref('users/'+uid).update({
pseudo: pseudo.value
})
}
Thanks all.

Azure Mobile Services - Alter User model on Insert script

I have a reservation model and a user model. In the insert script for my reservation model, I have the following:
function insert(item, user, request) {
response.send(200, 'test');
item.organizationid = user.organizationid;
if (user.hourstoreserve <= (item.endtime - item.starttime)) {
request.respond(400, 'You do not have the necessary hours available to make this reservation');
} else if (user.complaints >= user.complaintsallowed) {
request.respond(400, 'You are over your maximum number of allowed complaints this month.');
} else {
user.hourstoreserve = (user.hourstoreserve - (item.endtime - item.starttime));
request.execute();
};
};
I need to make sure that item, which should be my new reservation that I am inserting, gets an organizationid from my user. I also then want to make sure the user has it's hourstoreserve validated, and if the reservation is made the user's hourstoreserve should be lowered.
It seems like this script isn't being executed at all. The first response.send(200, 'test'); does not send a response.
I am calling this insert script from my custom api similar to the following:
var reservations = request.service.tables.getTable("reservations");
reservations.insert(newReservation);
The custom API call works and inserts the reservation as it should, it just doesn't seem to execute my insert script.
Any help is appreciated.
When you invoke the CRUD operations of the tables from the service itself (i.e., in the code of a custom API, scheduler or another table), the table scripts are not executed. There's an open feature request to have this feature added to the backend, please upvote it if you think it will help you.
Another problem which I see in your code - the user object which is passed to the insert script isn't an item from your user model; instead, it's the information about the logged in user to the service (i.e., in the client side, after calling one of the login operations, that will be the user information it will have). That object doesn't have any properties about organization id, hourstoreserve, etc. If you need to get that information, you'll need to query your users table and working with it directly.

Categories

Resources