Handle PayPal Smart Checkout Buttons with Laravel & ReactJS Frontend - php

I am having some trouble thinking this through the right way.
I am running Laravel as the backend for a ReactJS Frontend - separately.
It is going to be a small onlineshop only having PayPal as the Payment Gateway (using PayPal Smart Checkout Buttons) without User Registration.
React will call the Laravel API on payment initiation which will prepare the actual call to PayPal on server-side (get the price from database, in case user tampered with it, i take only the product ID and get the real product data from the database). The response will be returned to React.
As you might know PayPal works this way: create order in first API call, then capture the order in second API call ("create order" and "capture order" calls)
Laravel Endpoints that are called: "/create-paypal-transaction" and "/capture-paypal-transaction".
Currently (old version of this project was a monolithic laravel solution, no separate frontend) I store the response of the "capture order" API call in my DB as the final order / as the completed transaction. The result of the "create order" call is not stored in the DB. I do store the result of the "create order" call, with all its information (product, price, id, paypal_id etc.) in the session. Then, after capturing I load from the session to create the final order as a DB entry.
My trouble is: how do I securely realize this with a separate frontend and pass data from my first API call to my second API call?
I see only two options right now, maybe you guys can enlighten me:
Save the response from PayPal of the "create order"-call to my DB
via laravel and then, after approval & response of the "capture
order"-call, just update the stored order status from something
like "created" to "captured".
Use the response data from the first API call in React and pass it to the second API call to hit the Laravel & store the order if PayPal returns success.
Problems that I don't like with either method:
currently there is no Authentication method implemented (no JWT or Passport or any). I was going to go with Laravel default API Authentication as I have no Users - therefore Passport & JWT don't seem to fit perfectly. People checkout without any registration. Therefore:
if I go with 1. solution people could easily mess with the DB and create loads of orders ("create order" calls)
and the 2. solution is just no real solution. I will not trust client-side data.
So, please, please let me know if you got any idea how to do this the smart way. Maybe I just don't see the obvious right now, but it has been a long day and all the thought about right way to securely communicate have been making me tired...
Thanks in advance!

Both (1) and (2) are overly complex. When the client calls create-paypal-transaction, all it needs in response (in addition to anything of your own you want to provide for your own purposes) is the order id. That's it, that's all the client wants and needs to keep track of.
It will use that id when it calls capture-paypal-transaction, and your webserver can check that it is appropriate and valid (in the session) before attempting to do the capture. No database storage is necessary until you have a successful capture, although you are welcome to store in-progress orderIDs for debug purposes. They have no accounting value, and no security value outside the session.

Related

How to take info from a SQL Database to populate a json obj & encode object in base64 and send via post to an api using laravel [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed last month.
Improve this question
So our platform operates on Laravel/PHP/SQL/JS/Dart/Flutter/SQL/Firebase and our payment processor has an rest api in which we need to work with to send a digital invoice out for payment. Now the processor requires information (Basics Name, Email, Amount, Phone, Ipaddress, Order Number, etc.) to be included in the api call some of which won't be available or known until after the order is placed on our system. Necessitating a spinner widget to place the order in a pending payment status to then fire the api call to collect payment after. Additionally all requests made to the api need to be converted to base64 encoding prior to being sent over the api.
According to the api documentation It says that i need to create a json object containing all the required information and encode that data using Base64 Encoding which is then sent via a put request to the api to obtain a response alongside a Payment token which will then need to be stored to be called upon later using a callback api get request. I am trying to figure out the best way to accomplish this so that our payment flow becomes:
Customer Shops Via Web / App adding items to cart
Clicks or Taps on the Confirm Order Button
Our App/Platform creates a "draft order" with a order status of pending payment & sends the necessary information to our processor to generate a digital invoice & payment token where the token is stored in our database with the rest of the order data & processor then send a text message to the customer with a link to complete DIV (Digital Identity Verification) & collect payment for the order.
Customer then follows the link & completes payment where processor indicates if the given orders payment was successful or unsuccessful in it's system while our platform sends an additional api request using the payment tokens to get the current payment status for orders sitting in the "pending payment status" so our platform can mark the order as paid and update it's status to processing.
I know i will invariably receive a response of why does your payment methodology need to be so complex just get processing and go and as much as we would love for that to be the case, it simply is just not possible at the moment in our industry and current political climate. Forcing us to use this type of payment methodology to be able to operate or be restricted to simply being cash only.
To be honest I have not yet attempted, as i am still trying to map out what this needs in order to work and am seeking advice on the best practical way to accomplish this using the frameworks/stack that we operate on. Admittedly i am feeling slightly intimidated by this project since management just kind of threw this in my lap after losing our backend server side developer. I am not super familiar with Laravel and am somewhat familiar with PHP however most of my background is in Flutter, Dart, Kotlin, Swift, Html, CSS, JS, React & management does not seem to know the difference and somehow expect me to make this work.
This is the stack we are currently using
PHP/Laravel for our Administrative Control Panel. This is where this functionality needs to be added.
SQL for database.
Flutter/Dart for Mobile app / Front End.
Firebase for OTP/Push Notifications etc.
Query needs to be made to database after order placement grabbing order info and placing it into a json object
Expected result should look like:
{
'ipAddress':'123.456.789.012',
'merchantId': '1234567890',
'invoicenumber': '1234',
'firstName':'Mary',
'lastName':'Jane',
'email':'email#email.com',
'currency':'USD',
'amount' : '1000',
'redirectURL':'example.com',
'apiKey': 'Rw309njyNnklbkf9Pn6YNx68494292EV'
}
Where the json object data needs to be encoded using Base64 Encoding
Where the output of that encoding should look like this:
ew0KDQonaXBBZGRyZXNzJzonMTIzLjQ1Ni43ODkuMDEyJywNCg0KJ21lcmNoYW50SWQnOiAnWENwUjQyOTInLA0KDQonZmlyc3ROYW1lJzoncmFqZXNoJywNCg0KJ2xhc3ROYW1lJzonZ29uZGFsaXlhJywNCg0KJ2VtYWlsJzonZW1haWxAZW1haWwuY29tJywNCg0KJ2N1cnJlbmN5JzonVVNEJywNCg0KJ2Ftb3VudCcgOiAnMTAwMCcsDQoNCidyZWRpcmVjdFVSTCc6J2V4YW1wbGUuY29tJywNCg0KJ2FwaUtleSc6ICdSdzMwOW5qeU5ua2xia2Y5UG42WU54Njg0OTQyOTJFVicNCg0KfQ==
Which will also then need to be stored temporarily as a string with the field name of RTPRequest
Where the encrypted string is then passed via a post request to the api endpoint
Where the response from the api endpoint will include a payment token in the body which will be needed to be added to the database table row for the order that was just sent to the api
API get callback request is then sent requesting an updated payment status and if successful updates the payment status to paid and the orders status from pending payment to processing taking the user to from the order processing spinner to their orders page.
Thoughts, suggestions, advice etc...
That doesn't seem so complicated. If you're confident with the listed technologies you should be able to handle the Laravel stuff pretty easily, the documentation is good.
You'll need to expose some API routes (Routing, Controllers) that read/update data on your tables (Models) and make server-to-server API calls to your payment provider (HTTP requests)
The architecture of the logical flow will be the same as any other stack really.
draft order generated
user redirect to provider
provider directs user back to yourself with some status (or a webhook)
your back end handles the returned user / webhook

GetTransactionDetails without transaction id

I have website where I use PayPal NVP sandbox. Sometimes after successful payment of user, PayPal get back to my return URL very slow. Unless PayPal returns to my website with details I am unable to check whether user has completed the order (For all attempt website adds order id to the database) or not and that destroys website's work principle.
What I need is that I want to retrieve the data of transaction without transaction id if possible. Maybe with custom field or something else. If I would be able to check the transaction details without transaction id , then I would be able to handle the requests by user accordingly. Or if there is a way to get a transaction id somehow with the help of another variable that also fine as I will make checking after finding out the transaction id.
Current PayPal Checkout integrations give an immediate response of success/failure. There is no need for any redirect away from your site, and there is no need to wait for asynchronous IPN or webhook messages. Don't use such things.
Follow the PayPal Checkout integration guide and make 2 routes on your server, one for 'Create Order' and one for 'Capture Order' (see the optional step 5 in 'Add and modify the code'; you can use the Checkout-PHP-SDK). Both of these routes on your server should return/output only JSON data (no HTML or text). Inside the 2nd route, when the capture API is successful you should store its resulting payment details in your database (particularly purchase_units[0].payments.captures[0].id, which is the PayPal transaction ID) and perform any necessary business logic (such as sending confirmation emails or reserving product) immediately before forwarding your return JSON to the frontend caller.
Pair those 2 routes with the frontend approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server

Where to store dynamic data for paypal express checkout (digital goods)

Imagine a site like istockphoto or envato where the user can only purchase digital credits...
How would one implement this in the cleanest, easiest way using paypal's API's? The docs there are a bit confusing to navigate...
Aside from that general "best-practices" question, my guess was to start with the Integration Wizard at https://devtools-paypal.com/integrationwizard/ and select "Express Checkout - Digital goods"
After setting up some test accounts on the sandbox, I've kinda sorta got it working- but I'm confused how I track dynamic data across the session.
I.e. where would I securely store the "number of credits" and "userid" values so that it gets added to this user (who may not have an email address, nevermind one matching their paypal account) upon successful payment. Is a database/callback system necessary?
Assuming so for the time being, my guess is to maybe store the data in a database where the primary key is the TOKEN received at SetExpressCheckoutDG(), and prepopulated fields are the data I want to keep... and then the final confirm.php page will check the database at that token and implement that data... but something just seems strange about that, i.e. relying on a callback (could be timeouts, etc.) and I'm not sure if it's really the most secure way of doing it.
If using examples, please stick with PHP (not curl or other langs). Thanks!
You could just bounce this along with your calls. I'll use NVP for my examples
You set your digital goods in SetExpressCheckout. Inside, you pass how many credits the user is buying and set the PAYMENTREQUEST_0_CUSTOM with their user ID.
In GetExpressCheckoutDetails that data would be passed back to you so you could store it in some fashion (you would get their items and quantity, plus the user ID). Then, you finish with DoExpressCheckoutPayment.
If that still doesn't help let me know.

Integrating Card Payments with Codeigniter

I've built a web application and I am looking to integrate cardsave's direct payment API into the application. I was wondering if anyone had any advise on the best way to do this.
Cardsave provide standard code for integrating: Download Gateway Integration Pack ZIP file
When a payment is made I need to store the CrossPaymentsReference and payment amount in my database, the rest I will leave to cardsave's api I have thought of a couple of solutions which should potentially work:
1) Using Views for all of the code and on sucessful payment and use Ajax to update the database with the crossPaymentReference and payment amount on sucessfull completion, because it involves minimal editing of the code, but does have a minor security risk because it sends the reference at the client end.
2) Create a library with the payment system class, put the preprocess payments and process payment code into a controller and copy the form into a view, and just a have a small model to update the database on sucessfull payment's. (I'm guessing this is the best way.)
3) Edit everything and build an MVC version of the code
My latest project runs on CI 2.0. I’ve integrated a payment system such as Card Save with success (in my case I use Ogone, which is a Belgian company).
Below I’ve detailed a bit how I implemented the order and payment system.
The advice I can give you is the following.
Keep your products, orders and payments in separate tables.
Link products to orders via a reference table (don’t store e.g. a list of product ID’s in a field in the order)
Allow that a payment can only have one order, but an order can have multiple payments (but only one paid). This way when a payment fails (e.g. the user pressed cancel on Card Saves payment page), you can just create a new payment on your side and let the user retry (unless Card Save accepts that you do 2 payment request with the same payment ID).
Make a separate library (not controller) that handles successfully paid orders. This library would e.g. activate a subscription that the user bought, or make a work order for someone to ship the products. By keeping it in a separate library you can extend its functionality (e.g. if for a specific product you would need to do something new) without touching at your payment logic (thus preventing heavy retesting).
Generate hashes when posting data, or redirecting users to checkout pages, pages that prepare the payment and recalculate the hashes each time to prevent that someone tampered with the data you posted or that is in the URL.
Make sure everything works without AJAX and add AJAX afterwards.
Basically the ordering process I came up with is divided as follows:
User adds services (I don’t sell physical products) to basket (using a modified version of CI’s shopping cart)
When done user clicks “Order products” which does a POST to the controller Place_order. The controller Place_order does the following things:
Check if the user is still logged in (in my case everyone needs to register before)
Get the products that are in the shopping cart and checks if they actually exist in the database (you never know)
Create a new order in the database and add the products to the order in the DB
Place_order doesn’t output anything, but redirects the user on success to a controller Checkout. Here I don’t use POST. This way you can reuse the URL (e.g. if the user decides to stop, he can continue the payment later). The URL contains the order ID and a hash.
The Checkout controller does the following
Recalculate the hash to see if no one tampered with the URL
Check if the order exists and isn’t paid yet
Check if the order belongs to the user logged in
Create the payment if it doesn’t exist yet
Show a view with a button “Cancel order” and “Pay order”. This is actually a form that contains in a hidden field the payment ID and a hash of the payment ID.
When clicking “Pay order”, a POST is done to a controller Pay_order. I don’t use GET, because I want that users only come on this page by posting data that was set by the Checkout controller. If they use GET to come on the page an error is thrown. This controller does the following:
Recalculate the hash to see of no one tampered with the posted data
Check if the payment exists and is not yet paid
If all is OK, compose the view that contains the necessary info to be posted to the payment service
Show the view.
When the user presses “Go to payment service” all data is posted to Ogone where the user executes the payment
When the payment is completed (correct or not) Ogone redirects the user back to me to a controller Payment_successfull or Payment_other (for errors etc). In the Payment_succesfull I call a library Purchase_activator which takes the payment ID as input. This one looks up the order and activates the services the user just paid. In the other case (on error) the user is shown a view with the correct error message and an option to retry or cancel.

Processing user registration/data after payment is made?

I have a <textarea> along with user registration information that I only want to be processed (inserted to the database) after payment (I want to keep my database clear unnecessary registrations or things like people that register but change their mind about paying for the site services)
I mean, I could use sessions but are there any other ways?
I was looking for a gateway that'll pass these variables back to me after purchase.
Or perhaps just having the gateway API.
Now, I know gateways such as paypal allow advanced processes like these but I don't want to apply to their credit checks just in case they have a reason to reject me. I don't want to depend on one gateway, is there any other gateways that guarantee not to reject my gateway needs and allow me to make advanced processes like the ones mentioned above? If anyone knows about gateways that don't need credit-type checks to be accepted I would appreciate if one could be suggested.
Note: I know some people will suggest to keep the registration data since it's only a few kilobytes even if people won't use the site or pay for the services. Call me OCD but I like my database clean and to only have relevant users/data. I will end up doing this in the end if I don't find a solution that suits my needs, so please, don't suggest it. Thanks.
If you want to use simple form based integration, you aren't going to get around having rows in your table before the users has been processed, unless you want people stealing your service. The fact you want your "database clean" is naive. Just put a registered flag and delete periodically if you are really that OCD.
You must create a auth token (random unique string), and update the database of the current user that that token belongs to that user. You then pass the user to the payment gateway and also pass along the token you have assigned to that user.
The gateway will send the user back to a url of your choosing, along with the token you have assigned to that user. At this point you update the table for that user with that token.
Only you and the gateway know about the token, the user only sees it if they get a successful charge.
If you don't do this, anyone can find the url the gateway sends on successful charge, and just load it themselves, giving them free service.
Alternatively, you can use deeper integration, were you do a web service call to the payment gateway, if it succeeds, you update your row, if it fails, you don't. This subjects you to onerous PCI compliance regulations. Trust me you don't want to delve into that. Just avoid it and do not let your systems see any CC information.

Categories