Introduction
Securely integrating your custom app with Shopify requires authenticating every request so you can access a merchant’s store data without exposing credentials. Shopify adopts the industry-standard OAuth 2.0 protocol to grant scoped access tokens, allowing your app to perform only the actions it’s been authorized for. In this comprehensive guide, you’ll learn:
- The basics of OAuth 2.0 in Shopify
- How to register your app and define scopes
- The step-by-step OAuth authorization code flow
- Implementing the flow in a Node.js/Express app
- Storing and refreshing access tokens
- Verifying incoming webhooks and app proxy calls
- Best practices for security and user experience

By the end, you’ll have a rock-solid foundation for authenticating and authorizing every Shopify API request.
1. OAuth 2.0 Overview in Shopify
1.1 What Is OAuth 2.0?
OAuth 2.0 is an authorization framework enabling apps to obtain limited access to user accounts on an HTTP service, without sharing passwords. Key components:
- Authorization Code Grant: A two-step process where your app redirects the merchant to Shopify’s consent page, then exchanges a one-time code for an access token.
- Scopes: Fine-grained permissions (e.g.,
read_products
,write_orders
) that bound what your app can do.
1.2 Why Shopify Uses OAuth
- Security: No need for merchants to share credentials; tokens can be revoked or rotated.
- Granularity: Merchants see exactly which scopes they grant, building trust.
- Standardization: Familiar flow for developers and clear integration patterns.
2. Registering Your App and Defining Scopes
- Create a Partner App
- Log into your Shopify Partner dashboard.
- Under Apps, click Create app → Custom app.
- Configure App URLs
- App URL: Your server’s base (e.g.,
https://myapp.com
). - Redirection URL(s): Must include
https://myapp.com/auth/callback
.
- App URL: Your server’s base (e.g.,
- Select Scopes
- E.g.,
read_products, write_orders, read_customers
. - Only request the minimum you need to follow least-privilege.
- E.g.,
- Obtain Credentials
- Copy your API Key and API Secret Key to your environment.
3. The OAuth Authorization Code Flow
- Initiate Login
- Merchant clicks “Connect with Shopify” in your UI.
- Redirect to: perlCopyEdit
https://{shop}.myshopify.com/admin/oauth/authorize? client_id={API_KEY} &scope={SCOPES} &redirect_uri={REDIRECT_URI} &state={CSRF_TOKEN}
- Merchant Grants Consent
- Shopify shows the scopes and store name.
- Upon approval, Shopify redirects back with
code
andstate
.
- Verify CSRF Token
- Compare returned
state
to the one stored in session to prevent cross-site request forgery.
- Compare returned
- Exchange Code for Access Token
- POST to
https://{shop}.myshopify.com/admin/oauth/access_token
with: jsonCopyEdit{ "client_id": "{API_KEY}", "client_secret": "{API_SECRET}", "code": "{CODE}" }
- Shopify responds with
{ "access_token": "...", "scope": "..." }
.
- POST to
- Store the Token
- Save to your database against the merchant’s shop domain.
- Use this token for all subsequent API requests.
4. Implementing OAuth 2.0 in Node.js/Express
Below is a simplified Express example using express-session
:

jsCopyEditimport express from 'express';
import session from 'express-session';
import axios from 'axios';
import crypto from 'crypto';
const app = express();
app.use(session({ secret: 'your-secret', resave: false, saveUninitialized: true }));
const { SHOPIFY_API_KEY, SHOPIFY_API_SECRET, HOST } = process.env;
const SCOPES = ['read_products','write_orders'].join(',');
app.get('/auth', (req, res) => {
const shop = req.query.shop;
const state = crypto.randomBytes(16).toString('hex');
req.session.state = state;
const redirect = `https://${shop}/admin/oauth/authorize?` +
`client_id=${SHOPIFY_API_KEY}` +
`&scope=${SCOPES}` +
`&state=${state}` +
`&redirect_uri=${HOST}/auth/callback`;
res.redirect(redirect);
});
app.get('/auth/callback', async (req, res) => {
const { shop, code, state } = req.query;
if (state !== req.session.state) return res.status(403).send('Invalid CSRF token');
const tokenResponse = await axios.post(`https://${shop}/admin/oauth/access_token`, {
client_id: SHOPIFY_API_KEY,
client_secret: SHOPIFY_API_SECRET,
code,
});
const accessToken = tokenResponse.data.access_token;
// Persist accessToken + shop in DB…
res.send('App installed successfully');
});
5. Token Storage and Management
- Secure storage: Encrypt tokens at rest; restrict DB access.
- Token scope validation: On each API call, verify the stored scopes still match required scopes.
- Token revocation handling: If an API call returns 401, re-initiate OAuth or flag the app as uninstalled.
6. Verifying Webhooks and App Proxies
Even after OAuth, your app must verify that incoming webhooks or proxy requests truly originate from Shopify:6.1 Webhook HMAC VerificationjsCopyEditimport crypto from 'crypto';
function verifyWebhook(req) {
const hmac = req.get('X-Shopify-Hmac-Sha256');
const body = req.rawBody; // Buffer of the raw request body
const digest = crypto
.createHmac('sha256', SHOPIFY_API_SECRET)
.update(body, 'utf8')
.digest('base64');
return crypto.timingSafeEqual(Buffer.from(digest), Buffer.from(hmac));
}
6.2 App Proxy Signature
- App proxies add parameters
shop
,path_prefix
, andsignature
. - Recompute signature over sorted query parameters using HMAC SHA256 and compare.

7. Best Practices
- Use HTTPS Everywhere: Shopify requires secure URLs; avoid mixed content issues.
- Least-Privilege Scopes: Request only necessary scopes to minimize risk and encourage merchant trust.
- State Parameter: Always implement and verify a strong CSRF token (
state
). - Graceful Error Handling: Guide merchants to re-install or re-authenticate if tokens expire or are revoked.
- Session Management: Tie sessions to shop domains; clear sessions upon uninstallation webhooks.
Conclusion
OAuth 2.0 in Shopify provides a secure, transparent way to authenticate your custom app and interact with store data. By guiding merchants through the authorization flow, verifying CSRF tokens, exchanging codes for access tokens, and safeguarding those tokens—and by vetting all incoming webhooks and proxy requests—you establish a robust security posture. Follow the code examples and best practices outlined here to ensure every request to Shopify’s APIs is authenticated, authorized, and encrypted, delivering reliable integrations that merchants can trust.