Public API curl requests & Authentication/Tokens

Solved

Public API curl requests & Authentication/Tokens

PriceZag
Shopify Partner
10 0 0

Hi,

I'm Nicholas, lead developer at PriceZag, a platform that monitors stores competitors.

For the last 8 years we provided our customers with a direct integration to Shopify so they can import their products to our platform directly from Shopify, and also update the price in their store based on the competitors and their repricing rules.

Everything worked fine for all these years, and still does for old customers, but it seems Shopify changed something recently that makes the authentication fail for new customers, or at least for some of them.

 

We use curl to make requests to Shopify. We wrote our own code for handling requests so we cannot use any Shopify library (which isn't available anyway in the programming language we use).

The requests we make use the following URL format: https://key:password@storename.myshopify.com/admin/api/YYYY-MM/products.json

It has always worked very well, we ask our customers their storename, API key and password which they generate in their Shopify account for us, and curl simply uses the standard authentication method with these tokens.

But recently we get this error with new customers (while old customers have no problems) :

{"errors":"[API] Invalid API key or access token (unrecognized login or wrong password)"}

I've seen this whole thing about the OAuth method which seems unnecessary complicated. Despite having decades of experience in both back-end development and cryptography I still can't wrap my head around it. The docs available on Shopify's website are very confusing and don't get to the core of what the actual HTTP request should have or how we generate that with real code.

 

So can someone please help me with this?

If we stick to old school HTTP+SSL and nothing else (no library to depend on), what raw data should we send, and what should we ask our new customers?

Is that OAuth complicated method mandatory now? Did Shopify change this in the last few weeks?

 

Thanks!

Development Team at PriceZag competitor monitoring
Accepted Solution (1)

JiniApps
Shopify Partner
1 1 1

This is an accepted solution.

You can try the following

 

App Registration: Register your app in the Shopify Partners dashboard to obtain a client ID and secret.

Authorization Request: Direct users to the authorization URL to grant your app access:

 

GET 

 

https://{storename}.myshopify.com/admin/oauth/authorize?client_id={your_client_id}&scope={scopes}&redirect_uri={redirect_uri}​

 

 
Handle Redirect: After the user authorizes your app, Shopify will redirect to your specified redirect URI with a temporary code.
Exchange Code for Token: Use this code to request an access token:
 

 

 

POST https://{storename}.myshopify.com/admin/oauth/access_token
Content-Type: application/json

{
"client_id": "{your_client_id}",
"client_secret": "{your_client_secret}",
"code": "{the_code_received}"
}

 

 

Use Access Token: You will receive an access token in the response, which you'll use for your GraphQL requests.

 

 

 

POST https://{storename}.myshopify.com/admin/api/YYYY-MM/graphql.json
Headers:
"X-Shopify-Access-Token": "{access_token}"
"Content-Type": "application/json"

Body:
{
"query": "{
products(first: 10) {
edges {
node {
id
title
variants(first: 5) {
edges {
node {
id
price
}
}
}
}
}
}
}"
}

 

 

View solution in original post

Replies 6 (6)

Made4uo-Ribe
Shopify Partner
10100 2398 3034

Hi @PriceZag 

 

You might have to update your api since October version already came out. If you are using rest API, it is already deprecated

If this fixed your issue, Likes and Accept as Solution are highly appreciated. Coffee tips fuel my dedication.
Get experienced Shopify developers at affordable rates—visit Made4Uo.com for a quick quote!
Need THEME UPDATES but have custom codes? No worries, for an affordable price.
PriceZag
Shopify Partner
10 0 0

Thanks but even when using "2021-04" which a lot of our old customers still use successfully it doesn't seem to work for new customers.

I tried every version possible, but none seem to work with the standard HTTP "Authorization" header (which is what curl does when using the "user:password@host" format).

That's what I'm trying to understand. And the docs are extremely vague and complex about all this.

Development Team at PriceZag competitor monitoring
Made4uo-Ribe
Shopify Partner
10100 2398 3034

Are you using REST api? You need to swap to graphiql. See documentation here

If this fixed your issue, Likes and Accept as Solution are highly appreciated. Coffee tips fuel my dedication.
Get experienced Shopify developers at affordable rates—visit Made4Uo.com for a quick quote!
Need THEME UPDATES but have custom codes? No worries, for an affordable price.
PriceZag
Shopify Partner
10 0 0

Why so complicated? ...
Could you please explain me why it still works for our customers who use a token starting with "shpat" ?

How can our new customers also get a "shpat" token? What makes this "shpat" token different?

Development Team at PriceZag competitor monitoring

JiniApps
Shopify Partner
1 1 1

This is an accepted solution.

You can try the following

 

App Registration: Register your app in the Shopify Partners dashboard to obtain a client ID and secret.

Authorization Request: Direct users to the authorization URL to grant your app access:

 

GET 

 

https://{storename}.myshopify.com/admin/oauth/authorize?client_id={your_client_id}&scope={scopes}&redirect_uri={redirect_uri}​

 

 
Handle Redirect: After the user authorizes your app, Shopify will redirect to your specified redirect URI with a temporary code.
Exchange Code for Token: Use this code to request an access token:
 

 

 

POST https://{storename}.myshopify.com/admin/oauth/access_token
Content-Type: application/json

{
"client_id": "{your_client_id}",
"client_secret": "{your_client_secret}",
"code": "{the_code_received}"
}

 

 

Use Access Token: You will receive an access token in the response, which you'll use for your GraphQL requests.

 

 

 

POST https://{storename}.myshopify.com/admin/api/YYYY-MM/graphql.json
Headers:
"X-Shopify-Access-Token": "{access_token}"
"Content-Type": "application/json"

Body:
{
"query": "{
products(first: 10) {
edges {
node {
id
title
variants(first: 5) {
edges {
node {
id
price
}
}
}
}
}
}
}"
}

 

 

PriceZag
Shopify Partner
10 0 0

Thank you so much JiniApps!

This is finally clear, as you used some coder-friendly language (while Shopify docs seem to be written by bureaucrats rather then coders).

I have created a test store and successfully made all requests manually which ended up returning a final shpua_* token that we can then use for future requests.

 

For anyone visiting this page with the same issue and confused by Shopify docs I will summarize below what to do (in coder-friendly language) :

 

First, to answer my question "Why so complicated?", the obvious reason is that Shopify wants to be able to control and revoke API access to any third party (like us), either themselves or to let the store owner do that. They can also modify the permissions granted rather than revoking the whole thing.

 

So from the user perspective (the person having a Shopify store) the process goes like this:

  1. User clicks some "Connect my Shopify store" link on the third party's website (like us PriceZag)
  2. That links goes to their own store where they are prompted to grant permissions to that app called "PriceZag"
  3. They click an "Install" button and are redirected back to that third party's website
  4. That URL to which they are redirected thanks them for linking Shopify, but also gets from Shopify some URI parameters it will use for back-end requests.

 

So what coders must do for all that to happen:

 

1. The third party app (like us PriceZag) must create an account at partners.shopify.com where they define the name of the app and so on.

2. In that platform they get a "Client ID" and "Client Secret", each is a 32-long hex string (128 bits)

3. They also must define "Redirection URL(s)" which is not what sets the URL but what ALLOWS specific URL(s) to be used to redirect the user back to the website in the process I described above.

4. As JiniApps mentioned, the URL to which to send the Shopify user when then click some "Connect my Shopify store" button is: 


@JiniApps wrote:

 

https://{storename}.myshopify.com/admin/oauth/authorize?client_id={your_client_id}&scope={scopes}&redirect_uri={redirect_uri}​

 


This is NOT a request to make in the background, it is the URL the user must click on the front-end.

The "redirect_uri" is where the user goes back on our website after clicking "Install", so in our case it is:

 

&redirect_uri=https%3A%2F%2Fpricezag.com%2Fshopify-redirect

 

To this URL will be added some URI parameters which we must save.

What Shopify calls "scope" (vague bureaucrats language) in fact means "permissions". It our case it will be:

 

&scope=read_products%2Cwrite_products%2Cread_price_rules

 

There is also a &state= parameter to put, which is just an arbitrary random string which you get back when the user is redirect back to the website.

All this is explained here: https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/authorization-code-gr...

and the permissions ("scopes") are here: https://shopify.dev/docs/api/usage/access-scopes#authenticated-access-scopes

5. After clicking "Install that App" the user is redirected by Shopify to that "redirect_uri" which now contains various URI parameters:

&code= : a temporary 128-bit in hex format to save, they call it {authorization_code} in their docs. This is NOT how we make all future requests to the store, there's still one more step...

Besides "code" there are a few more useful URI parameters which you can see at step 2 in the link above, they are: hmac, host, shop, state, and timestamp.

6. Finally, as JiniApps mentioned, you make a back-end POST request using that "code" you got in the URL parameters when the user was redirected. With curl it would look like this:

 

curl -H 'Content-Type: application/json' -d '{"client_id":"my_app_id","client_secret":"my_app_secret","code":"that_code_from_redirect"}' 'https://THEUSERSTORENAME.myshopify.com/admin/oauth/access_token'

 

And you get this as a response:

 

{"access_token":"shpua_xxxxxxxxxxxx","scope":"write_products,read_price_rules"}

 

They call this "token exchange" (exchanging the "code" URI parameter for receiving a "shpua" token) and it's documented here: https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/token-exchange

7. You made it! Now you can use that shpua token for all future requests to that store by putting it as a "X-Shopify-Access-Token" HTTP header, for example: 

 

curl -H 'X-Shopify-Access-Token: shpua_xxxxxxxxxxx' 'https://THEUSERSTORENAME.myshopify.com/admin/api/2024-01/products.json?limit=3' | python -mjson.tool

 

 

Development Team at PriceZag competitor monitoring