.dev
Apps & OAuth

Scopes reference

Every OAuth scope, the implication hierarchy, and how grants are computed.

Scopes are plain strings stored on access tokens as abilities. The same vocabulary is used for store member RBAC and OAuth grants, so a token's power reads exactly like a team member's permissions.

Platform scopes

ScopeGrants
authIdentity only — "Sign in with Feeef". Read the user's profile, nothing else. Default when an app registered no scopes.
appsDeveloper access to per-user app data (/apps/:id/user-data/users/:userId)
*Everything. The consent screen shows an elevated warning; request only for trusted first-party tooling.

Store scopes

ScopeGrants
storeFull store access — implies every store-level scope below
store.readRead store profile and settings
store.settingsUpdate store settings, delete store
store.integrationsManage integrations & webhooks; also implies finance* and inventory*
store.membersManage team members and their scopes

Commerce scopes

Each parent implies its .read child.

ScopeResource
orders / orders.readOrders — create, update, status changes / read-only
products / products.readProducts and variants
categories / categories.readCategories
shipping_prices / shipping_prices.readShipping price matrices
finance / finance.readFinancial accounts, entries, analytics (Pro)
inventory / inventory.readWarehouses, stock, reservations (Pro)

Content scopes

ScopeResource
pages / pages.readStore pages
product_landing_pages / product_landing_pages.readLanding pages
template_components / template_components.readCustom template components
store_templates / store_templates.readStore templates

Hierarchy rules

  • A parent implies its .read child: ordersorders.read.
  • store implies all store.* scopes.
  • store.integrations additionally implies finance, finance.read, inventory, inventory.read (integration-gated modules).
  • * implies everything.

Checks are hierarchy-aware: a token with orders passes an orders.read requirement.

How grants are computed

The single source of truth is computeGrantedScopes — used for both the consent display and the token's abilities:

  1. scope param present → grant the requested scopes that the app's registration allows (hierarchy-aware). If the intersection is empty → invalid_scope error. Never a silent fallback.
  2. No scope param → grant the app's registered scopes. An app registered with * grants ['*']. An app with no registered scopes grants ['auth'] — never full access.

Enforcement

Enforcement is rolling out incrementally. Currently enforced routes include:

RouteRequired scope
stores/:id/integrations*, webhooksstore.integrations
PUT/PATCH /stores/:id (settings)store.settings (store.integrations for integrations-only patches)
DELETE /stores/:idstore.settings
Member add/removestore.members
GET|PUT /apps/:id/user-data/users/:userIdapps + token bound to the app

Failing a check returns 403:

{ "error": "insufficient_scope", "requiredScope": "store.integrations" }

with a WWW-Authenticate: Bearer ... scope="store.integrations" header (RFC 6750).

Request the minimum scopes your integration needs. Users see the list at consent, and narrower requests convert better. You can always re-authorize with broader scopes later.

On this page