Shopify OAuth 2.0: What Actually Happens When a Merchant Installs Your App
OAuth is the first thing your app handles and the first thing Shopify reviewers check. Here's the complete flow, the gotchas, and how to get it right.
Every Shopify app starts with OAuth. It's the mechanism that lets a merchant install your app and grant it access to their store data. Get it wrong, and your app won't install — or worse, it'll be a security vulnerability. Let's walk through exactly what happens, step by step.
Step 1: The Install Redirect
When a merchant clicks 'Install' on your app listing (or visits your app's install URL), Shopify redirects them to your app's auth endpoint with parameters: `shop` (the myshopify.com domain), `hmac` (a signature for verification), and `timestamp`. Your app must verify the HMAC using your API secret — this proves the request actually came from Shopify, not a malicious third party.
Step 2: Requesting an Access Token
After HMAC verification, your app redirects the merchant to Shopify's OAuth page at `https://{shop}.myshopify.com/admin/oauth/authorize` with your `client_id`, requested `scopes` (like `read_products,write_orders`), and a `redirect_uri`. The merchant sees a consent screen listing the permissions your app is requesting. This is where scope creep becomes visible — only request what you actually need.
Step 3: The Callback and Token Exchange
Once the merchant approves, Shopify redirects back to your `redirect_uri` with a temporary `code`. Your server then makes a server-to-server POST to `https://{shop}.myshopify.com/admin/oauth/access_token` with your `client_id`, `client_secret`, and the `code`. Shopify responds with a permanent access token (for offline tokens) or a short-lived session token (for online tokens).
Offline vs Online Tokens
This is a critical decision. Offline tokens persist until the merchant uninstalls your app — ideal for background jobs, webhooks, and automated tasks. Online tokens expire after a short period and are tied to a specific user session — required for apps that need to act on behalf of the currently logged-in user. Most apps need offline tokens for core functionality. You can request both during the OAuth flow.
Common Pitfalls
Here's what trips developers up: (1) Not verifying HMAC — this is a security vulnerability and an instant App Store rejection. (2) Storing tokens in plain text — always encrypt at rest. (3) Not handling token rotation — Shopify is moving toward session tokens with automatic refresh. (4) Requesting too many scopes — reviewers will reject your app if you request `write_products` but never actually write products. (5) Not handling app uninstallation — when a merchant removes your app, Shopify fires an `app/uninstalled` webhook. You must clean up stored tokens and data.
How ShopForge Handles This
In the ShopForge scaffold, OAuth is fully implemented out of the box. The `shopify.server.ts` file configures the OAuth flow using `@shopify/shopify-app-remix`, handles HMAC verification, stores session tokens in your database via Prisma, and manages token refresh automatically. You configure your scopes in one place, and the scaffold handles the rest — including the webhook registration for app uninstallation.