Development discussions around Shopify APIs
So I've been trying to get this to work but no matter what I do I keep getting a 403 error.
I'm passing the token to the backend but when it hits verifyRequest({ returnHeader: true }) it just keeps giving me a 403 error.
Need help with this ASAP since I already wasted enough time on this.
contact me luisgarciacode@gmail.com
_app.js
import ApolloClient from "apollo-boost";
import { ApolloProvider } from "react-apollo";
import App from "next/app";
import { AppProvider } from "@shopify/polaris";
import { Provider, useAppBridge } from "@shopify/app-bridge-react";
import { authenticatedFetch, getSessionToken } from "@shopify/app-bridge-utils";
import { Redirect } from "@shopify/app-bridge/actions";
import "@shopify/polaris/dist/styles.css";
import translations from "@shopify/polaris/locales/en.json";
import axios from "axios";
function userLoggedInFetch(app) {
const fetchFunction = authenticatedFetch(app);
return async (uri, options) => {
const response = await fetchFunction(uri, options);
if (
response.headers.get("X-Shopify-API-Request-Failure-Reauthorize") === "1"
) {
const authUrlHeader = response.headers.get(
"X-Shopify-API-Request-Failure-Reauthorize-Url"
);
const redirect = Redirect.create(app);
redirect.dispatch(Redirect.Action.APP, authUrlHeader || `/auth`);
return null;
}
return response;
};
}
function MyProvider(props) {
const app = useAppBridge();
getSessionToken(app).then(token => console.log('token = ', token))
const authAxios = axios.create();
authAxios.interceptors.request.use((config) => {
return getSessionToken(app)
.then((token) => {
console.log(token)
config.headers["Authorization"] = `Bearer ${token}`;
return config;
})
})
const client = new ApolloClient({
fetch: userLoggedInFetch(app),
fetchOptions: {
credentials: "include",
},
});
const Component = props.Component;
return (
<ApolloProvider client={client}>
<Component {...props} authAxios={authAxios} />
</ApolloProvider>
);
}
class MyApp extends App {
render() {
const { Component, pageProps, host } = this.props;
return (
<AppProvider i18n={translations}>
<Provider
config={{
apiKey: API_KEY,
host: host,
forceRedirect: true,
}}
>
<MyProvider Component={Component} {...pageProps} />
</Provider>
</AppProvider>
);
}
}
MyApp.getInitialProps = async ({ ctx }) => {
return {
host: ctx.query.host,
};
};
export default MyApp;
{/* <AppBridgeWithShopify>
<GraphqlConnection>
<Component></Component>
</GraphqlConnection>
</AppBridgeWithShopify> */}
server.js
import "@babel/polyfill";
import dotenv from "dotenv";
import "isomorphic-fetch";
import createShopifyAuth, { verifyRequest } from "@shopify/koa-shopify-auth";
import Shopify, { ApiVersion } from "@shopify/shopify-api";
import Koa from "koa";
import next from "next";
import Router from "koa-router";
import {PrismaClient} from '@prisma/client';
import { storeCallback, loadCallback, deleteCallback } from './custom-sessions.js';
import bodyParser from 'koa-bodyparser';
import slugify from "slugify";
const {user, faq} = new PrismaClient();
dotenv.config();
const port = parseInt(process.env.PORT, 10) || 8081;
const dev = process.env.NODE_ENV !== "production";
const app = next({
dev,
});
const handle = app.getRequestHandler();
Shopify.Context.initialize({
API_KEY: process.env.SHOPIFY_API_KEY,
API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
SCOPES: process.env.SCOPES.split(","),
HOST_NAME: process.env.HOST.replace(/https:\/\//, ""),
API_VERSION: ApiVersion.October20,
IS_EMBEDDED_APP: true,
// This should be replaced with your preferred storage strategy
// SESSION_STORAGE: new Shopify.Session.MemorySessionStorage(),
SESSION_STORAGE: new Shopify.Session.CustomSessionStorage(
storeCallback,
loadCallback,
deleteCallback
),
});
// Storing the currently active shops in memory will force them to re-login when your server restarts. You should
// persist this object in your app.
// const ACTIVE_SHOPIFY_SHOPS = {};
app.prepare().then(async () => {
const server = new Koa();
const router = new Router();
server.use(bodyParser());
server.keys = [Shopify.Context.API_SECRET_KEY];
server.use(
createShopifyAuth({
async afterAuth(ctx) {
// Access token and shop available in ctx.state.shopify
const { shop, accessToken, scope } = ctx.state.shopify;
console.log(ctx.state)
console.log(ctx.state.shopify)
const host = ctx.query.host;
// ACTIVE_SHOPIFY_SHOPS[shop] = scope;
// const newUser = await user.upsert({
// where:{ store: shop},
// update: {store: shop, scope: scope, updated_at: new Date().toISOString()},
// create: {store: shop, scope: scope, updated_at: new Date().toISOString()}
// })
const response = await Shopify.Webhooks.Registry.register({
shop,
accessToken,
path: "/webhooks",
topic: "APP_UNINSTALLED",
webhookHandler: async (shop) =>
await user.delete({where: {shop: shop}}),
});
if (!response.success) {
console.log(
`Failed to register APP_UNINSTALLED webhook: ${response.result}`
);
}
// Redirect to app with shop parameter upon auth
ctx.redirect(`/?shop=${shop}&host=${host}`);
},
})
);
const handleRequest = async (ctx) => {
await handle(ctx.req, ctx.res);
ctx.respond = false;
ctx.res.statusCode = 200;
};
router.post("/webhooks", async (ctx) => {
try {
await Shopify.Webhooks.Registry.process(ctx.req, ctx.res);
console.log(`Webhook processed, returned status code 200`);
} catch (error) {
console.log(`Failed to process webhook: ${error}`);
}
});
router.post(
"/graphql",
verifyRequest({ returnHeader: true }),
async (ctx, next) => {
await Shopify.Utils.graphqlProxy(ctx.req, ctx.res);
}
);
// FAQ Routes
router.post(
"/faq",
verifyRequest({ returnHeader: true }),
async (ctx, next) => {
const {title, description} = ctx.request.body;
let user_id = await user.findFirst({
where: { store: ctx.query.shop}
})
user_id = user_id.id
const newFaq = await faq.create({
data: {
title: title,
slug: slugify(title, '_'),
description: description,
user_id: user_id,
dynamic: false,
updated_at: new Date().toISOString()
},
})
return ctx.body = {
status: 'success',
data: newFaq
}
console.log(newFaq)
}
);
router.put(
"/faq/:id",
verifyRequest({ returnHeader: true }),
async (ctx, next) => {
await Shopify.Utils.graphqlProxy(ctx.req, ctx.res);
}
);
router.del(
"/faq/:id",
verifyRequest({ returnHeader: true }),
async (ctx, next) => {
await Shopify.Utils.graphqlProxy(ctx.req, ctx.res);
}
);
router.get("(/_next/static/.*)", handleRequest); // Static content is clear
router.get("/_next/webpack-hmr", handleRequest); // Webpack content is clear
router.get("(.*)", async (ctx) => {
const shop = ctx.query.shop;
// console.log('ACTIVE_SHOPIFY_SHOPS')
// console.log(ACTIVE_SHOPIFY_SHOPS)
const checkShop = await user.findFirst({
where: { store: shop}
})
// This shop hasn't been seen yet, go through OAuth to create a session
if (checkShop === null) {
ctx.redirect(`/auth?shop=${shop}`);
} else {
await handleRequest(ctx);
}
});
server.use(router.allowedMethods());
server.use(router.routes());
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
});
Solved! Go to the solution
This is an accepted solution.
Forget it I figured it out.
The issue was in the custom session storage not working properly.
This is an accepted solution.
Forget it I figured it out.
The issue was in the custom session storage not working properly.
can you please share the working solution?
User | RANK |
---|---|
12 | |
6 | |
5 | |
5 | |
5 |
Learn these 5 things I had to learn the hard way with starting and running my own business
By Kitana Jan 27, 2023Would you love to unleash the unbridled power of the Google Shopping Channel into your sho...
By Gabe Jan 6, 2023How can you turn a hobby into a career? That’s what Emmanuel did while working as a wa...
By Skye Dec 30, 2022