Server side API call in Shopify cart page - shopify

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.

Related

How to securely validate payment and send product

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)

best practices for authentication in react native

I'm a beginner in react native and I'm creating an app. I've done some research about how to make a secured react native app, but I didn't found much information. I've come up with a "solution" myself, but I want to make sure this is the right way to do this. So I need the help of some react native/javascript/security experts if possible, to quickly check if my approach is OK or not?
I have included 3 questions in this text, but obviously they're related. I've put them in bold. Feel free to answer one or more questions, I appreciate every answer!
I'm creating an app in react native. For a user to be able to use the app, the user should create an account and sign in. I'm using an JSON web token as an access token to authorize the requests made from the app to the server, and to identify the user (I store the user ID in the JSON web token).
At my server, I first check if the access token is valid. If so, I get the user ID out of the access token and use this user ID to identify the user.
For extra security, I'm also using refresh tokens, because an access token is only valid for 10 minutes. When a user send a request with an expired access token, the server responds with a 401 not authorized status.
To make my code more "managable", I've created a wrapper function in react native. I wrap every "request function" (every function where I do a GET/POST/PUT/DELETE request to the server) with this wrapper function. This wrapper function checks the response of the request. If the response status is 200, the response is returned to the code. If the response status is 401, the refresh token is send to a specific endpoint to obtain a new access token. When the access token arrives at the app, the previous request is made again with the new access token. The wrapper function also stores the new access token in (temporary) redux (keychain or shared preferences). 1. Is a wrapper function a good idea? For me, it's more manageble because now I'm reusing the code.
Every time the user opens the app, a new access token is requested, and when a user closes the app, the current access token is deleted, even if it is not expired yet. That way, I want to make sure that every app "session" starts with a new access token. 2. Is this okay? Or should I prevent unnecessary requests to the server when I still have a (possibly) valid access token?
In my react native app, this wrapper function is located in a context component. This "authentication" context is wrapper around my other components in App.js like this:
<AuthenticationProvider>
<AppNavigator />
</AuthenticationProvider>
This way, my wrapper function is accessible to all my other components. My authentication context looks like this:
const AuthenticationContext = createContext({
accessToken: null,
wrapperFunction: () => {}
})
const AuthenticationProvider = (props) => {
let accessToken = null
const refreshToken = useSelector(state => state.auth.refreshToken)
const wrapperFunction = () => {
// wrapper function
// set the access token
// await fetch('server endpoint')...
}
return (
<AuthenticationContext.Provider value={{ accessToken, wrapperFunction }}>
{props.children}
</AuthenticationContext.Provider>
)
}
3. Is using a context a good practice to do stuff like this?
Server-side, I store every refresh token in a database. When a user requests a new access token, I check if the sent request token still exists in the database. If not, I have revoked access for this user and the user should be logged out. This way, I want to make sure I can "manage" users.
Yes, it makes sense. Actually I can't think of a better way to manage the scenario you mentioned. When you wanna temper the request before it's sent, you will need a single function to do so. You could also use some hooks e.g. onBeforeSend and onAfterReceive, but in your case I don't see any extra value for this.
I do not agree with the deletion of a valid token. You can still send request to server on every app start to get user's last data -might have changed on another device-. I don't understand the logic of starting the app with a new session -maybe more information?
I don't think you need to pass the wrapperFunction/token using context. It would be best if you could send user data by context. you wrapper function can access the token directly from asyncStorage. And each component can call the function directly by importing it.
I believe you are taking the approach of using a wrapper function since the relevant API requests are made directly in components. The best practice is to move such requests outside (E.g. Redux actions with a middleware like redux-thunk) the components.
It's better to check if the access token is expired (by decoding the token) before sending the API request and retrieve the new access token. This will reduce the amount of requests to server. You can implement a common request method which handle this check as well.
I think since your access token expires every 10 mins this is unnecessary. Is there a specific reason to start each session with a new access token?
You can pass in user access details using the context. I think it's matter of preference. Passing in the wrapper function is not needed if you're handing the requests through a common request method.

How to manually authenticate user/client in spartacus?

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

Save information immediately after Google login in Azure Mobile Services (.NET Back-end)

What I basically want to be able to do is authenticate to azure mobile services (using google or some other provider), and immediately save some of the user information (i.e. email address) on the server.
I know I could call a custom method from the app after authentication, but I was hoping to have some hook to do this straight after the google login on the server side.
Is this possible? How do I do it?!
This is currently only possible in the .NET runtime. If using the Node runtime, you will not be able to do this.
For the .NET runtime, you would want to create a class which inherits from GoogleLoginProvider (I'll call mine CustomGoogleLoginProvider), and then you'll need to override the CreateCredentials method:
public override ProviderCredentials CreateCredentials(ClaimsIdentity claimsIdentity)
{
// grab any information from claimsIdentity which you would like to store
// If you need the access token for use with the graph APIs, you can use the following
string providerAccessToken = claimsIdentity.GetClaimValueOrNull(ServiceClaimTypes.ProviderAccessToken);
// use the access token with HttpClient to get graph information to store
return base.CreateCredentials(claimsIdentity);
}
Then in your WebApiConfig.cs, add the following to the Register() method, immediately after the options object is created:
options.LoginProviders.Remove(typeof(GoogleLoginProvider));
options.LoginProviders.Add(typeof(CustomGoogleLoginProvider));
The CreateCredentials() method gets called immediately before a Mobile Services token is created. At this point, the Google token has been validated, and the claimsIdentity has been populated with whatever Google sent back.
Some information will be available in the claimsIdentity by default, but you may also have information which requires you to call through to Google. You can only do this if you set the proper scopes configured.
If you did want to go the custom API route, you would just need to make a call from your controller:
ServiceUser user = (ServiceUser)this.User;
GoogleCredentials creds = (await user.GetIdentitiesAsync()).OfType<GoogleCredentials>().FirstOrDefault();
string accessToken = creds.AccessToken;
The Node version of getIdentities() is documented here.

How to access facebook session id in an fbml application?

I am working on an fbml application which can be added to a fan page. The application then sends ajax request to my php script for data etc.
I have to store some data on my php side against a key or something which remains the same throughout facebook session. How can I implement this? Is there any way to send facebook session id in ajax request? I am using fbml Ajax() element to send ajax request.
Here's a glimpse of code
function do_ajax(path)
{
var sessionKey = '###'; //Something representing fbml app's session state
var ajax = new Ajax();
ajax.responseType = Ajax.FBML;
ajax.ondone = function(data) {
document.getElementById('content').setInnerFBML(data);
}
ajax.post(path+'/'+sessionKey);
}
The visitor may or may not be logged in so I can't use userid. And php session id keeps changing in each request.
Thanks a lot
FBML is being deprecated. See: https://developers.facebook.com/docs/reference/fbml/ No more support for it in 10 days, and then in 6 months it will no longer work. I would suggest using the new Javascript SDK.