Last active
April 19, 2018 18:30
-
-
Save cdaz5/053d4524b81d492ba066bd6b0a6cb884 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ///////////// 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://509cee43.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}`)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment