How access tokens work in this template and when they get invalidated.
You run a local Express server exposed via an HTTPS tunnel. Opening the Shopify-generated install link for the app triggers the OAuth flow - Shopify redirects back to your callback, the server exchanges the code for an access token, and stores it in a local SQLite database via Prisma. After that the server is never needed again.

Every script reads the token directly from the SQLite database and attaches it as an X-Shopify-Access-Token header on each request to the Admin GraphQL API. No server, no session management - just a direct authenticated request from your terminal.
The server has three routes, each with a clear responsibility:
GET / - The install gate. Shopify redirects here when the app is opened from the admin, including hmac and shop query parameters. The server validates the HMAC to confirm the request is genuinely from Shopify (direct access without these returns 403), then checks the database for an existing session. Only if no session is found does it start the OAuth flow. If already installed, it shows the currently granted scopes and a re-authorize link — this is how you pick up new scopes after shopify app deploy.GET /auth - Starts the OAuth flow, redirecting to Shopify's authorization screen.GET /auth/callback - Exchanges the authorization code for an access token and stores the session. Also handles stale callback URLs (e.g. refreshing the page after install) by detecting the specific Shopify error and returning a meaningful response based on whether a session already exists.
Shopify offers three OAuth flows for getting an access token. Two were ruled out:
That leaves Authorization Code Grant - the standard OAuth flow for non-embedded apps. It works with any store, but requires standing up a server to handle the callback. This template provides that server so you only run it once. Shopify docs
The token could live in .env, a JSON file, or be hardcoded. SQLite + Prisma was chosen because: