I am building a website for a masseur with VueJS + Strapi, and clients can buy a gift voucher.
Right now I have the VueJS part set-up with a Paypal payment gateway.
I am wondering how to set-up the back-end part and how to trigger the creation of the voucher.
What I was planning to do is send the response from paypal (onApprove) to the back-end and create a new voucher in the database then send it through e-mail to the recipient.
onApprove: async (data, actions) => {
const order = await actions.order.capture();
axios.post('myapiroute', order)
},
Is this secure ? (if I use CORS to only allow my front-end's adress to make calls to the back-end API)
Is there a way to "bypass" cors or force the front-end to make API calls ?
Is there a more secure way to do this ?
Do not use actions.order.create / .capture to create and capture orders on the client side if you need to perform any server-side actions (such as writing to a database or sending to a product) as a result of that capture.
The order creation and capture should instead be done from server-side code, with whatever backend you have (apparently node.js in this case; there is a Checkout-NodeJS-SDK available).
Make two routes on your server, one for 'Create Order' and one for 'Capture Order', documented here. These routes should return only JSON data (no HTML or text). The latter one should (on success) store the payment details in your database before it does the return (particularly purchase_units[0].payments.captures[0].id, the PayPal transaction ID)
Pair those two routes with the following approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server
(Since you are using a vue frontend you can look at this vue-specific sample, but change its createOrder and onApprove to fetch from your backend)
Related
I am exposing REST API's via an API Gateway so the requests go
Client => API Gateway => Back-end.
My back-end REST API's need to know about 2 users
1: Target User (on some requests)
the API needs this data for its action eg: groups/{abc}/add-user needs to know which user to add to a group
2: Calling User (on every request):
the API needs to check that this user is allowed to perform the action eg: only a group admin may add another user to the group.
I don't want other developers to get confused when looking \ adding to my API's so I want to create a convention. Is it a good idea to add the calling user ID as a header on every request?
eg: "user-context": "12345"
Before everyone screams "INSECURE!!!!", I should add some info to put your minds at ease
The calling user is allowed to know their user-id. It's not a problem
The target user is not identified by their real user-ID but by an obfuscated ID
The calling-user-id is actually passed in a signed JWT to my API Gateway. The API-Gateway validates the JWT, takes the calling-user-id and adds it to the back-end request. What i'm really asking here is whether the API-Gateway should put the calling-user-id in the header (eg: "user context": "12345") or the query string /myapi/?calling-user-id=12345
I've tried both approaches and they both work. I'm wanting to know which approach makes the most sense to other developers.
I have an e-commerce customer who uses Shopify APIs to create an order (a customer who purchased an item).
From a created command (which can contain different items), I must generate a file with some attributes like weight or the destination address.
I was drowning in their public documentation and honestly can't get over it (I don't have much programming experience).
I would like to know which APIs (or services...) I have to request in your opinion please?
Given what I'm being asked, I don't know if I can find all this info with a single API or I have to call several methods to build my file little by little...
For example, I have no idea, really no idea to know if a given command is fragile or not. I don't even know if they communicate such information by their API.
Thanks in advance
If you want realtime (as soon as the order is created, the file is created) : You need to register a webhook.
A Shopify webhook is simply a script that, on a certain event, send the event's data to a link.
Example : An order placed webhook (predefined Shopify webhook) will send the order's data to an URL in JSON format as soon as the order is placed.
So you will need a server running 24/7 (get a VPS for less than 5 bucks a month). The server will listen at an ip at a certain port.
You will setup Shopify's webhook to send data to that ip / port.
Step 1: Create your server
You will need any backend framework for this. I choose NodeJs + Express framework, because it is so easy to do with it.
Here is a sample code :
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 3000;
app.use(bodyParser.json());
app.post('/', function (req, res) {
let body = req.body;
console.log(body);
});
let server = app.listen(port, function () {
let host = server.address().address;
console.log('Example app listening at http://%s:%s', host, port); //Copy this to your clipboard, you will need it in step 2
});
Step 2: Register Shopify Webhook
Go to your client's store, add /admin/settings/notifications to the url.
Scroll to the bottom of the page, click Create Webhook, chose Order creation as an event, JSON format, Lastest as API version. Paste the IP / Port you copied earlier into URL.
Step 3: Check the data sent by Shopify
From here, you can check the data Shopify sent you. It will be printed by your NodeJs server.
It is in JSON format, so you can do all kinds of stuff with it. Filter important info, and output to file for example.
If you want to check everytime your script starts and not realtime : you need to create a custom app in your client's store, and use GraphQL
Shopify won't let you check for certain orders by order number, and the limit of their API is 250. Using GraphQL, you can do this, but you need to know GraphQL (a little more advanced).
You can check their docs at shopify.dev
right now I'm trying to create a proof of concept on spartacus. The concept is to manually check out a cart for an anonymous customer.
I came to a point, where I was wondering whether it is possible to authenticate a client or user manually with spartacus.
So my question in general: What is the best practice to manually authenticate the client/user in spartacus? Some code examples would be great :)
Best regards and thanks in advance
Not sure exactly what you mean by "manually" authenticate.
In spartacus if you want to authenticate the client (the app) it's quite simple. The client-token.interceptor is setup to catch request containing a specific header and add the client token to the request. If Spartacus doesn't have the token in memory it will request it.
To do so you should use add the USE_CLIENT_TOKEN to your request header. Here is an example:
const url: string = '/url';
let headers = new HttpHeaders({
'Content-Type': 'application/json',
});
// The line bellow add the token to the header
headers = InterceptorUtil.createHeader(USE_CLIENT_TOKEN, true, headers);
return this.http
.post<User>(url, { data: data }, { headers });
As for the user authentication, the user token will be added to all request as long as the user is authenticated in Spartacus. There is no "automatic" mechanism to fetch it. The token is fetched via login.
Hope this helps!
There are a few things you have to do in case of a guest checkout.
First thing is to enable guest checkout in the config with:
checkout: { guest: true }
Then the first step of the checkout should be /checkout-login page.
There user needs to provide email address that is assigned to a specific cart.
We recognize guest checkout by that assigned email to the cart. Otherwise, checkout components will behave like it is normal checkout. Because of that, there are calls for user addresses or payments.
In case you want everything on one page (setting email address, delivery, payments etc.) you have to override default implementation for checkout components to avoid all these calls for the logged user.
And calls for setting address and payment in case of guest checkout doesn't have to by authorized (you can see that on demo guest checkout these calls have undefined in Authorization header).
And for client authorization, it is nicely described in https://stackoverflow.com/a/60821200/4666829
We are currently calling third party(our API to OPT-IN that user in our system) API using ajax in cart page for OPT-IN feature. Consider that user is already created in our system at the time of registration using webhook. Now just need to OPT-IN that user.
But by calling API using ajax we are making Access Token Visible. So, it's not secure way to implement API'S.
Need API call to create shopify public APP. In that checking the user status in our system using API. Depending upon API response have to decide Show/Hide one button (that button is added in cart page.). I am talking about implementation of our API for creating APP. That API need Access Token which is provided by us.
So, for security purpose of access token need to implement server side API in Shopify cart page.
async function getData(){
const result= await fetch("https://s15.socialannex.net/apiv2/userstatus/SITE_ID/{{ customer.email }}?access_token=ACCESS_TOKEN",{
method: 'POST',
data: {
'first_name': 'Atul'
},
});
var res = await result.json();
if(res.error_code == 0){
$(".join-loyalty-button").css("display","none");
}
}
Above code is working fine but its ajax call. I want to call above API at server side.
You want to use the App Proxy pattern. See the documentation here:
https://help.shopify.com/en/api/guides/application-proxies
With that, you can callback using Ajax to your API with any information important to your callback. Example, the customer ID. The callback is secure, and no security tokens are exposed. You can return JSON meaning your front-end code can show/hide buttons based on an answer from your internal App.
So, There are multiple ways a client can pass values to server. Request Body, Header and/or Cookies.
On the server side these values could be retrieved by ModelBinders, ValueProviders MediaFormatters, FromBody, FromUri, Dependency Inject a component that reads it from current http Context or Read from current HTTP context directly ( I know this is the worst one for unit testing. So, never do that).
The question is how to decide which to be used for what.
What I think is for all the user input use ModelBinder. For anything else, like authentication token in header dont use the model binder but a authentication attribute. Which reads from the header or cookie.
What about the case where you have somthing like a cartId and you are updating the Items in cart, Shipping address, Payment address etc. Now, using DDD Cart must be the root object and Items, shipping address and payment must be the child and each request must receive a cart and the dependent object. But, that would be a really heavy load. So, why not to pass around only cartId and why not to store that cartId in cookie and if we do that. How should we read the value of cartId, use a ModelBinder, Dependency Inject a component that reads it from current http Context or Read from current HTTP context directly ( I know this is the worst one for unit testing. So, never do that)
So, any id that is not an auth token or a session token and is required in the action method. But it is not being passed as an input in request body or query strings. What is the best approach to read parameters like that
What about the case where you have somthing like a cartId and you are
updating the Items in cart, Shipping address, Payment address etc.
Now, using DDD Cart must be the root object and Items, shipping
address and payment must be the child and each request must receive a
cart and the dependent object.
Don't confuse DDD with HTTP/REST. DDD is for your domain. HTTP/REST is for your web resources.
Why not something like this?
add product to the cart
POST /my/carts/1/products { body/model: productId=6&quantity=2 }
update quantity
PUT /my/carts/1/products/6 {body/model: quantity=4 }
...and I have to argue with your DDD design. Shipping and billing addresses are really parts of the Order aggregate, not the Cart aggregate. But I digress...
If you organize your HTTP resources to mimic your DDD aggregates, then you don't need to pass the whole cart in with each request. You can have different user actions call different resources/method combinations to interact with the aggregate. You don't even need to send the cartId in with the body of the request, because it is already in the URL:
[POST("my/carts/{cartId:int}/products")]
public HttpResponseMessage PostProduct(int cartId, CartProductPostModel model)
{
// ensure user owns the cart (based on cookie or authentication info)
// get the cart aggregate based on the cartId,
// add the product to the cart
// tell the client you succeeded by passing back an appropriate response
// 201 Created
// Location: http://www.site.com/my/carts/1/products/6
// note the response does not send back the whole cart, it only tells you
// the new resource was created and where you can access it
}
If you design your HTTP resource URL's RESTfully, then you don't need to pass around any id's in headers, cookies, session, etc, because all of the information you need is already in the request -- either in the URL itself, or in the request body.
Update
So, in our case cartId is not an integer it is a string that actually
has some "/"s (IIS/ASP.net MVC blows up). I know weird but thats how
it is and I can't change it. So, it can't be there as part of url. It
could be part of a query-string. But, to make it inter operate with
someother clients. We are kind of forced to put it on cookie.
Yes you can put it in the URL. You just have to encode it first. So a cart ID like cart/with/slashes ends up like this in the URL:
add product to the cart
POST /my/carts/cart%2fwith%2fslashes/products
update quantity
PUT /my/carts/cart%2fwith%2fslashes/products/6
This will work just fine with either MVC or WebAPI routing without blowing up.
[POST("my/carts/{cartId}/products")]
public HttpResponseMessage PostProduct(string cartId, CartProductPostModel model)
{
// cartId will be "cart/with/slashes", decoded
}