I ran into this tutorial using every technology in the world which is supposed to show how to build a react app from the ground up to leverage the shopify API. However there also this page describing a simple API call to do more or less what I need.
The goal is to have an entirely custom (extremely simple) checkout process that ends up in the shopify system. It would go something like this:
Stripe purchase ok -> shopify order saved -> thank you page redirect.
EDIT: It appears that the format https://api_key:api_secret.#my-store.myshopify.com/admin/api/2019-07/orders.json solves the authentication problem. The call:
GET https://key:secret#my-test-store.myshopify.com/admin/api/2019-07/orders.json
returns a pleasant
{
"orders": []
} so the authentication is a-ok.
However, doing a POST https://key:secret#my-test-store.myshopify.com/admin/api/2019-07/orders.json
Seems to return a cryptic page, instead of an error like so (which simply leads to your demo store/app):
So, in summary, I have a store, an authorized app (which successfully authenticates) so how do I add an order for an existing SKU programmatically?
Are you sure there are no cookies on the request? Because I can reproduce your exact issue if I add cookies.
It might be easier to use curl in order to have absolute clarity into what is being posted. For example:
# Edit to change app hostname, key/secret, and product/variant/customer ids
curl -X POST 'https://key:secret#so57018447.myshopify.com/admin/api/2019-07/orders.json' \
-H 'Content-Type: application/json' \
-d '{
"order": {
"line_items": [
{
"product_id": 2017449607219,
"variant_id": 17985741619251,
"quantity": 1
}
],
"customer": {
"id": 1257159000115
},
"financial_status": "pending"
}
}
'
Response:
{
"order": {
"id":952834392115,
"email":"",
"closed_at":null,
"created_at":"2019-07-15T14:38:18-04:00",
...
But if you want to stick with Postman, here are the supporting screenshots showing success without cookies, and failure with:
Confirming there are no cookies set:
Successful post to orders.json endpoint:
Now, add a cookie:
And I get the response shown in your question:
If you read the documentation of the private apps
Shopify doesn't support cookies in POST requests that use basic HTTP authentication. Any POST requests that use basic authentication and include cookies will fail with a 200 error code. Using cookies with basic authentication can expose your app to CSRF attacks, such as session hijacking.
https://help.shopify.com/en/api/getting-started/authentication/private-authentication
This is on purpose, doing this on a client side is criminal. If you are doing something server side then it is ok to use basic auth. But on client side you shouldn't be using it
If you want to use in postman then you need to use it with access_token
Private apps can authenticate with Shopify by including the request header X-Shopify-Access-Token: {access_token}, where {access_token} is replaced by your private app's Admin API password.
Related
I am inheriting a backend Express API and a front end React app.
Currently I am using cookie-parser in my POST /login API like so:
res.cookie('something', 'abc123', {
maxAge: COOKIE_MAX_AGE
});
on my front end app, there is a function for checking if an auth token exists:
export function isAuthCookiePresent() {
console.log('ALL COOKIES:', cookies.get());
return (
cookies.get(AUTH_COOKIE_NAME) && cookies.get(AUTH_COOKIE_NAME) !== null
);
}
And as expected I see { something: 'abc123' } in my console logs.
However, when I try logging in this using autodeployed branches in Vercel (https://vercel.com/), the cookie is missing.
I was under the impression that cookies were supposed to be set on the front end? But in the code the cookie is being set on the backend. And I don't see anything in the code that passes it to the front end. I thought I would find something on the front end like that would have a "upon successful login, execute cookies.set("x-auth-token", res.body.token)"
It's odd to me that it works locally at all. Would someone mind explaining how this works? I thought cookies were stored in the browser on the client side. But if that was true, why does cookie-parser even exist in express and why is it being used server side?
However, when I try logging in this using autodeployed branches in Vercel (https://vercel.com/), the cookie is missing.
This is because it appears you are setting the cookie server side, and as far as I know vercel only handles client side and will not let you use express.
I was under the impression that cookies were supposed to be set on the front end? But in the code the cookie is being set on the backend. And I don't see anything in the code that passes it to the front end. I thought I would find something on the front end like that would have a "upon successful login, execute cookies.set("x-auth-token", res.body.token)"
Cookies can actually be set through headers (Set-Cookie: <cookie-name>=<cookie-value>), which is what express's res.cookie does. MDN's article on the Set-Cookie header says:
The Set-Cookie HTTP response header is used to send a cookie from the server to the user agent, so the user agent can send it back to the server later. To send multiple cookies, multiple Set-Cookie headers should be sent in the same response.
It's odd to me that it works locally at all. Would someone mind explaining how this works? I thought cookies were stored in the browser on the client side. But if that was true, why does cookie-parser even exist in express and why is it being used server side?
Cookies are, in fact, stored client-side. They are accessible through client side javascript and backend with the cookie header. The cookie-parser module is needed to parse the name=value syntax sent by the Cookie header (Cookie - HTTP | MDN). It's being used server-side becuase validating cookies in the frontend can let any user give a false "true" value to your if statement that you use to validate cookies.
As an answer to the question: I recommend backend because JWTs have to be signed, and setting and signing them client-side will let anyone sign an arbitrary payload.
I'm trying to get information about videos hosted by Vimeo (from my client's channel, so no rights issues). I'm using Javascript, specifically d3.js.
The request works fine when using the old API, with this type of url :
http://vimeo.com/api/v2/video/video_id.output
For instance, this works in d3.js :
d3.json("http://vimeo.com/api/v2/video/123456789.json", function(error,data){
console.log(data);
}):
But I can't get the new API to work as easily in a simple request, using this type of url for instance :
https://api.vimeo.com/videos?links=https://vimeo.com/123456789
What do I need to do ? Authenticate ? If so, how ? I'd be grateful to get examples in either jQuery of d3.
Vimeo's API documentation is not the best, so you have to dig a little around to actually get the information you need. In your case, you do not need to go through the whole OAuth2 loop if you are simply requesting data from endpoints that do not require user authentication, such as retrieving metadata of videos, as per your use case.
First, you will need to create a new app, by going to https://developer.vimeo.com/apps:
You can simply generate a Personal access token from your Vimeo app page under the section that says Generate an Access Token:
Remember that this token will only be visible once (so copy it when it is generated): and you have to keep it secure! The access token should be part of the Authorization header's bearer token. If you are using cURL, it will look like this:
curl -H "Authorization: Bearer <YourPersonalAccessToken>" https://api.vimeo.com/videos/123456789
Therefore, while you can do the following on your page to retrieve video metadata on the clientside, note that you are actually exposing your private token to the world:
d3.json("https://api.vimeo.com/videos/123456789/")
.header("Authorization", "Bearer <YourPersonalAccessToken>")
.get(function(error, data) {
console.log(data);
});
However, I strongly recommend that you proxy this request through your own server, i.e. create a custom endpoint on your server, say /getVimeoVideoMetadata. This API endpoint will receive the video ID, and will add the secretly stored access token you have on your server before making the request. This will mask your access token from your website visitors.
I'm currently implementing OAuth login with LinkedIn in my React and Play app and am running into a CORS error when trying to redirect to the authorization page in my dev environment:
XMLHttpRequest cannot load https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_i…basicprofile&redirect_uri=http%3A%2F%2Flocalhost%3A9000%2Fusers%2Flinkedin. Redirect from 'https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_i…basicprofile&redirect_uri=http%3A%2F%2Flocalhost%3A9000%2Fusers%2Flinkedin' to 'https://www.linkedin.com/uas/login?session_redirect=%2Foauth%2Fv2%2Flogin-s…' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
I have the following setup:
Play server running at localhost:9000
React app (created via create-react-app) running at localhost:3000
My JS code calls the /auth/linkedin endpoint which is implemented as follows:
Action { implicit req: RequestHeader =>
val csrfToken = CSRF.getToken.get.value
Redirect(linkedinUrl(oauthConfig.linkedinClientId, csrfToken)).withSession("state" -> csrfToken)
}
I have my Play application set to handle CORS appropriately.
My react app just makes a request to the above endpoint via Axios:
axios.get('/auth/linkedin')
This responds with a 303 with a redirect to the LinkedIn auth page which then gives me the error.
How do I get the CORS policy working correctly in this dev setup? I've tried adding the following to my package.json as the create-react-app documentation recommends:
"proxy": "http://localhost:9000",
And I've also tried setting a request header to "Access-Control-Allow-Origin" : "*" on the redirect in the Play server with no success.
Note that going to localhost:9000/auth/linkedin redirects properly.
https://www.linkedin.com/oauth/v2/authorization responses apparently don’t include the Access-Control-Allow-Origin response header, and because they do not, your browser blocks your frontend JavaScript code from accessing the responses.
There are no changes you can make to your own frontend JavaScript code nor backend config settings that’ll allow your frontend JavaScript code to make requests the way you’re trying directly to https://www.linkedin.com/oauth/v2/authorization and get responses back.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS explains in more detail but the gist of it is: for CORS, the server the request is being sent to must be configured to send the Access-Control-Allow-Origin response header, nor your own backend server.
2019-05-30 update
The current state of things seems to be that when needing to do LinkedIn authorization, you’ll have to initiate the request from your backend code. There’s no way you can do it from your frontend code, because LinkedIn no longer provides any support for it at all.
LinkedIn did previously provide some support for handling it from frontend code. But the page that documented it, https://developer.linkedin.com/docs/getting-started-js-sdk, now has this:
The JavaScript SDK is not currently supported
And https://engineering.linkedin.com/blog/2018/12/developer-program-updates has this:
Our JavaScript and Mobile Software Development Kits (SDKs) will stop working. Developers will need to migrate to using OAuth 2.0 directly from their apps.
So the remainder of this answer (from 2017-06-13) has now become obsolete. But it’s preserved below for the sake of keeping the history complete.
2017-06-13 details, now obsoleted
Anyway https://developer.linkedin.com/docs/getting-started-js-sdk has official docs that explain how to request authorization for a user cross-origin, which appears to be just this:
<script type="text/javascript" src="//platform.linkedin.com/in.js">
api_key: [API_KEY]
onLoad: [ONLOAD]
authorize: [AUTHORIZE]
lang: [LANG_LOCALE]
IN.User.authorize(callbackFunction, callbackScope);
</script>
And https://developer.linkedin.com/docs/signin-with-linkedin has docs for another auth flow:
<script type="in/Login"></script> <!-- Create the "Sign In with LinkedIn" button-->
<!-- Handle async authentication & retrieve basic member data -->
<script type="text/javascript">
// Setup an event listener to make an API call once auth is complete
function onLinkedInLoad() {
IN.Event.on(IN, "auth", getProfileData);
}
// Handle the successful return from the API call
function onSuccess(data) {
console.log(data);
}
// Handle an error response from the API call
function onError(error) {
console.log(error);
}
// Use the API call wrapper to request the member's basic profile data
function getProfileData() {
IN.API.Raw("/people/~").result(onSuccess).error(onError);
}
</script>
I ran into a similar problem, so let's divide this problem into detailed steps
Hit request to get the code(from frontend)
now send this code to the backend
In the backend, make another call to LinkedIn OAuth API and get the access token
With this access token make 3 separate calls to get the name, profile picture
and email of the user(yes you heard that right you need to make 3 separate calls and also the response JSON format is not very appealing)
Visit this for the detailed step-by-step process, it involves a lot of things. I can just share the process here but for the actual implementation visit this.
https://www.wellhow.online/2021/04/setting-up-linkedin-oauth-and-fixing.html
What could be done is:
window.location.href='http://localhost:9000/auth/linkedin'
The urlEndPoint could be directly to linkedIn's API or a back-end service which makes the call to linkedIn's API.
I've deployed a Let's Chat application for my own server.
However, instead of using currently built, original Let's Chat web application I would like to develop my own, using its API.
And according to Let's Chat wiki:
Revoke an API Token
In the top-left dropdown menu:
Select "Auth tokens"
Click "Revoke token"
Choose "Yes". This will delete any previously generated token.
Basic Authentication
Use the API token as the username when authenticating. The password
can be set to anything, but it must not be blank (simply because most
clients require it).
So far I've generated own token and tried to send GET request to retrieve all rooms that I have in the app, but I've got an error: 401 - Unauthorized - I've tried to send this request with { data: my_token, password: my_random_password } credentials but without success. So my main question is: how exactly I can authenticate with Let's Chat API using ajax request?
I couldn't find any API url / endpoint dedicated for such task - please help.
EDIT:
I've tried also setting headers but it still doesn't work:
$.ajax({
url: CHAT_URL + 'rooms',
beforeSend: function(xhr){
xhr.setRequestHeader('username', 'NTczYzZ1111111111111111111JiMWE3MGUwYThiNzZhYjhmYjFjOWJkOTQ5ZDQ2YjhjNWUyMzkwNmMzYjhjMQ==');
xhr.setRequestHeader('password', '123qwe');
}
}).done(function(resp){
console.log('1');
console.log(resp);
}).done(function(resp){
console.log('2');
console.log(resp);
});
From that wiki page:
Use the API token as the Bearer token.
This is done by setting the header Authentication to the value bearer YOUR_TOKEN_HERE
So,
xhr.setRequestHeader('Authentication', 'bearer NTczYzZ1111111111111111111JiMWE3MGUwYThiNzZhYjhmYjFjOWJkOTQ5ZDQ2YjhjNWUyMzkwNmMzYjhjMQ==');
If you want to use basic authentication, this answers that question
How to use Basic Auth with jQuery and AJAX?
I am currently in the process of implementing a server-side OAuth2 flow in order to authorize my application.
The JS application will be displaying YouTube Analytics data on behalf of a registered CMS account to an end user (who own's a channel partnered with the CMS account). As a result of this, the authorization stage needs to be completely hidden from the user. I am attempting to authorize once, then use the 'permanent' authorization code to retrieve access tokens as and when they're needed.
I am able to successfully authorize, and retrieve an access code. The problem begins when i attempt to exchange the access code for a token.
The HTTP POST Request to achieve this needs to look like this...
POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
Content-Type: application/x-www-form-urlencoded
code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=8819981768.apps.googleusercontent.com&
client_secret={client_secret}&
redirect_uri=https://oauth2-login-demo.appspot.com/code&
grant_type=authorization_code
I am using this code to achieve this:
var myPOSTRequest = new XMLHttpRequest();
myPOSTRequest.open('POST', 'https://accounts.google.com/o/oauth2/token', true);
myPOSTRequest.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
myPOSTRequest.send('code=' + myAuthCode + '&redirect_uri=http%3A%2F%2Flocalhost%2FCMSAuth3.html&client_id=626544306690-kn5m3vu0dcgb17au6m6pmr4giluf1cle.apps.googleusercontent.com&scope=&client_secret={my_client_secret}&grant_type=authorization_code');
I can successfully get a 200 OK response to this Request however no access token is returned, and myPOSTRequest.responseText returns an empty string.
I have played with Google's OAuth Playground - and can successfully get a token using my own credentials.
Am i missing something here?
You cannot do this, because there is the same origin policy. This is a security concept of modern browsers, which prevents javascript to get responses from another origin, than your site. This is an important concept, because it gives you the ability, to protect you against CSRF. So don't use the code authorization flow, use instead the token authorization flow.
Try and build up the full URL. Then dump it in a webbrowser. If its corect you will get the json back. You have the corect format.
https://accounts.google.com/o/oauth2/token?code=<myAuthCode>&redirect_uri=<FromGoogleAPIS>&client_id=<clientID>&client_secret={my_client_secret}&grant_type=authorization_code
Other things to check:
Make sure that you are using the same redirect_uri that is set up in google apis.
How are you getting the Authcode back? If you are riping it from the title of the page i have had issues with it not returning the full authcode in the title try checking the body of the page. This doesnt happen all the time. I just ocationally.