Qasim
Qasim

Reputation: 41

Getting error Oauth error invalid_request: The redirect_uri is not whitelisted from Shopify API access through local host?

I have looked at the other shopify questions here but this time the error seems to come from something else I believe. I am trying to create/access a shopify app through localhost on nodejs for playing around with the Product API in the future. But encountering the above error:

Here is my NGROK log:

GET  /shopify                  302 Found                                                                                GET  /shopify                  302 Found                                                                                GET  /shopify                  302 Found                                                                                GET  /shopify                  302 Found                                                                                GET  /shopify                  302 Found                                                                                GET  /shopify                  302 Found

1- Here is my index.js file:

///////////// Initial Setup /////////////

const dotenv = require('dotenv').config();
const express = require('express');
const crypto = require('crypto');
const cookie = require('cookie');
const nonce = require('nonce')();
const querystring = require('querystring');
const axios = require('axios');

const shopifyApiPublicKey = process.env.SHOPIFY_API_PUBLIC_KEY;
const shopifyApiSecretKey = process.env.SHOPIFY_API_SECRET_KEY;
const scopes = 'write_products';
const appUrl = 'https://20a11edc124f.ngrok.io/';

const app = express();
const PORT = 3000

app.get('/', (req, res) => {
  res.send('Ello Govna')
});

///////////// Helper Functions /////////////

const buildRedirectUri = () => `${appUrl}/shopify/callback`;

const buildInstallUrl = (shop, state, redirectUri) => `https://${shop}/admin/oauth/authorize?client_id=${shopifyApiPublicKey}&scope=${scopes}&state=${state}&redirect_uri=${redirectUri}`;

const buildAccessTokenRequestUrl = (shop) => `https://${shop}/admin/oauth/access_token`;

const buildShopDataRequestUrl = (shop) => `https://${shop}/admin/shop.json`;

const generateEncryptedHash = (params) => crypto.createHmac('sha256', shopifyApiSecretKey).update(params).digest('hex');

const fetchAccessToken = async (shop, data) => await axios(buildAccessTokenRequestUrl(shop), {
  method: 'POST',
  data
});

const fetchShopData = async (shop, accessToken) => await axios(buildShopDataRequestUrl(shop), {
  method: 'GET',
  headers: {
    'X-Shopify-Access-Token': accessToken
  }
});

///////////// Route Handlers /////////////

app.get('/shopify', (req, res) => {
  const shop = req.query.shop;

  if (!shop) { return res.status(400).send('no shop')}

  const state = nonce();

  const installShopUrl = buildInstallUrl(shop, state, buildRedirectUri())

  res.cookie('state', state) // should be encrypted in production
  res.redirect(installShopUrl);
});

app.get('/shopify/callback', async (req, res) => {
  const { shop, code, state } = req.query;
  const stateCookie = cookie.parse(req.headers.cookie).state;

  if (state !== stateCookie) { return res.status(403).send('Cannot be verified')}

  const { hmac, ...params } = req.query
  const queryParams = querystring.stringify(params)
  const hash = generateEncryptedHash(queryParams)

  if (hash !== hmac) { return res.status(400).send('HMAC validation failed')}

  try {
    const data = {
      client_id: shopifyApiPublicKey,
      client_secret: shopifyApiSecretKey,
      code
    };
    const tokenResponse = await fetchAccessToken(shop, data)

    const { access_token } = tokenResponse.data

    const shopData = await fetchShopData(shop, access_token)
    res.send(shopData.data.shop)

  } catch(err) {
    console.log(err)
    res.status(500).send('something went wrong')
  }
});

///////////// Start the Server /////////////

app.listen(PORT, () => console.log(`listening on port ${PORT}`));

2- Here is my env file

SHOPIFY_API_PUBLIC_KEY=key here
SHOPIFY_API_SECRET_KEY=key here

3- Here is my package.json file

{
  "name": "TestQasim",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "axios": "^0.20.0",
    "cookie": "^0.4.1",
    "dotenv": "^8.2.0",
    "express": "^4.17.1",
    "nodemon": "^2.0.4",
    "nonce": "^1.0.4"
  }
}

Im using NGROK tunneling and using this link:

https://20a11edc124f.ngrok.io/shopify?shop=testqasim121312.myshopify.com

but getting the above mentioned error.

I have checked the API URLS etc and cannot seem to find any issue in those either.

this is a screenshot of the error

this is a screenshot of the error

Upvotes: 0

Views: 5192

Answers (6)

theshubhagrwl
theshubhagrwl

Reputation: 1026

For people reading this in 2025. Here are a few things to keep in mind

When using an app built with cli

Make sure that your app URL and redirect URL have the same base URLs, e.g APP URLs

https://2fc8-3354.ngrok-free.app/

Redirect URLs

https://2fc8-3354.ngrok-free.app/auth/callback
https://2fc8-3354.ngrok-free.app/auth/shopify/callback
https://2fc8-3354.ngrok-free.app/api/auth/callback

For me the trailing slash in App Url didn't matter.

Second, I did a silly mistake which left me puzzled for hours.

When you start a ngrok and point it to your localhost, it is not guaranteed that your localhost and ngrok are on the same port. Your localhost can be on port 3000 but your ngrok URL may be running on port 5092. So when you star the ngrok see what port it is using.

After that you can simply use the --tunnel-url <ngrok-url>:<port> syntax

shopify app dev -- --tunnel-url <ngrok URL>:<port>

Upvotes: 0

Ravi Thummar
Ravi Thummar

Reputation: 5608

Check your ngrok URL with your app setup URL and Allowed redirection URL(s). Both should be the same like HTTPS or HTTP check properly.

Upvotes: 0

qskane
qskane

Reputation: 521

In my case, Shopify automatically generates the .env file and automatically adds the redirect URL whitelist, but the problem is that Shopify auto-populates the wrong values.

The autofill value is https://36f6-45-251-107-111.ngrok.io/auth/callback

The correct value is: https://36f6-45-251-107-111.ngrok.io/shopify/auth/callback

So please check if the redirect URL is consistent with the whitelist after decoding the URL in the error page.

Upvotes: 0

greazzy
greazzy

Reputation: 41

Incase you're still facing this issue,

Remove the trailing slash from the appURL, I think that should fix this issue.

Use const appUrl = 'https://20a11edc124f.ngrok.io'

not const appUrl = 'https://20a11edc124f.ngrok.io/'

and don't forget to restart your node server.

Upvotes: 4

rrallvv .J
rrallvv .J

Reputation: 1

For someone who has the same problem later, I leave a message. I just solved it.

In your package.json, you might have this command. => "dev": "node server.js"

It never restart your server when code is edited. So, after chaing ngrok address(ex, https://12k1ml2kd1m.ngrok.io), restart your server.

In short, change your ngrok address and restart your node server.

Upvotes: 0

David Lazar
David Lazar

Reputation: 11427

Log into your partner account, and for the App with the API keys, whitelist the url. It really is that simple.

Upvotes: -2

Related Questions