dist/codex/saleor-commerce/skills/saleor-security/SKILL.md
Secure Saleor applications — JWT authentication, OIDC integration, App tokens, permission model, rate limiting, CORS, and security headers. Use when configuring Saleor security.
npx skillsauth add orcaqubits/agentic-commerce-claude-plugins saleor-securityInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Fetch live docs:
site:docs.saleor.io authentication JWT tokens for current JWT authentication flowsite:docs.saleor.io apps permissions for App token authentication and permission modelsite:docs.saleor.io OIDC OpenID Connect for OIDC integration configurationsaleor webhook payload signature JWS verification for webhook signature verificationhttps://docs.saleor.io/docs/developer/app-store/apps/overview for App authentication patternssaleor CORS security headers production for CORS and header configurationSaleor uses JSON Web Tokens for staff and customer authentication. Tokens are obtained via GraphQL mutations and passed as Bearer tokens.
| Operation | GraphQL Mutation | Token Type | Expiry |
|-----------|-----------------|------------|--------|
| Customer login | tokenCreate | Access + Refresh | Access: 5 min, Refresh: 30 days |
| Staff login | tokenCreate | Access + Refresh | Access: 5 min, Refresh: 30 days |
| Refresh | tokenRefresh | New access token | 5 min (configurable) |
| Verify | tokenVerify | Validity check | N/A |
| Deactivate | tokensDeactivateAll | Invalidate all | N/A |
Authorization: Bearer <token> headerSaleor supports OpenID Connect for federated authentication. Saleor acts as an OAuth client, delegating login to an external identity provider.
| Mode | Description | Use Case | |------|-------------|----------| | Saleor as OAuth client | Delegates login to external IdP | SSO with corporate directory | | Authorization Code flow | Standard OIDC flow with code exchange | Web applications | | ID token login | Accept ID token from external IdP | Mobile or SPA apps |
OIDC_JWKS_URL — JSON Web Key Set endpoint of the IdPOIDC_OAUTH_CLIENT_ID — Client ID registered with IdPOIDC_OAUTH_CLIENT_SECRET — Client secret for code exchangeApps authenticate using App tokens (permanent Bearer tokens) rather than JWT:
| Token Type | Obtained Via | Expiry | Scope |
|-----------|-------------|--------|-------|
| App token | appTokenCreate mutation | Never (manual revoke) | App's declared permissions |
| Auth token (install handshake) | Token exchange during install | Session-scoped | Full App permissions |
Saleor uses a granular permission system applied to staff users, permission groups, and Apps.
| Permission | Grants Access To |
|-----------|-----------------|
| MANAGE_PRODUCTS | Create, update, delete products, variants, types |
| MANAGE_ORDERS | View and modify orders, fulfillments, returns |
| MANAGE_APPS | Install, configure, and remove Apps |
| MANAGE_USERS | Manage customer accounts |
| MANAGE_STAFF | Manage staff users and permission groups |
| MANAGE_CHECKOUTS | Access and modify checkouts |
| MANAGE_CHANNELS | Create and configure channels |
| MANAGE_SHIPPING | Configure shipping zones and methods |
| MANAGE_DISCOUNTS | Manage promotions, vouchers, gift cards |
| MANAGE_TRANSLATIONS | Manage translations for all entities |
| MANAGE_SETTINGS | Access to site-wide settings |
| MANAGE_PAGE_TYPES_AND_ATTRIBUTES | Manage page types and attribute schemas |
| MANAGE_PRODUCT_TYPES_AND_ATTRIBUTES | Manage product types and attribute schemas |
| HANDLE_PAYMENTS | Process transactions and refunds |
| HANDLE_TAXES | Configure tax providers |
is_superuser) bypasses all permission checksTHROTTLE_CLASSES in Django settings| Setting | Description | Example |
|---------|-------------|---------|
| ALLOWED_ORIGINS | Origins permitted to make requests | ["https://storefront.example.com"] |
| ALLOWED_HOSTS | Hostnames the server responds to | ["api.example.com"] |
| CORS_ALLOW_CREDENTIALS | Allow cookies cross-origin | true for Dashboard |
| CORS_ALLOW_HEADERS | Additional allowed headers | ["authorization-bearer", "content-type"] |
django-cors-headers middleware (included in Saleor)CORS_ALLOW_ALL_ORIGINS = True in production| Header | Value | Purpose |
|--------|-------|---------|
| Strict-Transport-Security | max-age=31536000; includeSubDomains | Enforce HTTPS |
| X-Content-Type-Options | nosniff | Prevent MIME-type sniffing |
| X-Frame-Options | DENY or SAMEORIGIN | Prevent clickjacking |
| Content-Security-Policy | Directive-based | Restrict resource loading |
| Referrer-Policy | strict-origin-when-cross-origin | Limit referrer leakage |
SECRET_KEY, never in source codeSECURE_SSL_REDIRECT = True in Django settingsSECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") behind a reverse proxySESSION_COOKIE_SECURE = True and CSRF_COOKIE_SECURE = TrueSaleor signs every webhook with the Saleor-Signature header. Since 3.5+, the default is JWS (RS256) using a public key from /.well-known/jwks.json. Legacy HMAC-SHA256 (via App secret) is deprecated and will be removed in 4.0.
<saleor-domain>/.well-known/jwks.jsonsaleor-app-sdk built-in middleware for automatic verification| Item | Action |
|------|--------|
| HTTPS | Enable SECURE_SSL_REDIRECT, set cookie secure flags |
| SECRET_KEY | Strong random value, environment variable only |
| ALLOWED_HOSTS | Restrict to actual domain names |
| CORS | Restrict to known origins |
| DEBUG | Set DEBUG = False in production |
| Database | Use SSL connections, restrict network access |
| App tokens | Rotate periodically, grant minimal permissions |
| Webhook signatures | Always verify JWS/HMAC on every webhook handler |
| Rate limiting | Enable throttling on all public endpoints |
| Dependencies | Pin versions, audit with pip-audit or safety |
| Admin access | Use permission groups with least-privilege |
| Logs | Never log tokens, secrets, or PII |
ALLOWED_HOSTS and CORS to prevent host header attacks and cross-origin abuseFetch the security documentation for current JWT authentication flow, OIDC configuration, and permission model before implementing.
development
Build with Spree's headless Next.js storefront — the official `spree/storefront` repo (Next.js 16 App Router with Server Actions and Turbopack, React 19 Server Components, Tailwind CSS 4, TypeScript 5, `@spree/sdk`, Sentry), server-only auth (httpOnly JWT cookies + publishable key), MeiliSearch faceted catalog, one-page checkout with Apple/Google Pay/Klarna/Affirm/SEPA, multi-region market routing, GA4 + JSON-LD SEO, and Vercel/Docker deployment. Use when forking or customizing the storefront, or evaluating headless adoption.
tools
Build Spree extensions as Rails engines — gem scaffolding, `bin/rails g spree:extension`, mounting routes/migrations/assets, the modern `prepend` decorator pattern (`*_decorator.rb` with `self.prepended(base)`), generators (`spree:model_decorator`, `spree:controller_decorator`), the four customization surfaces in preference order (Events > Webhooks > Dependencies > Decorators), Spree::Dependencies for swapping service objects, gem release/versioning, and the deprecated Deface engine. Use when building a reusable Spree extension or adding non-trivial customization to an app.
development
Build with Spree's event bus and Webhooks 2.0 — `Spree::Events` publication, `Spree::Subscriber` DSL with `subscribes_to` and `on`, wildcard matching, lifecycle events (`{model}.created/.updated/.deleted` via `publishes_lifecycle_events`), the canonical event catalog (order.*, payment.*, shipment.*, product.*), Webhooks 2.0 endpoints, HMAC-SHA256 signing (`X-Spree-Webhook-Signature`), exponential-backoff retries, and Sidekiq job orchestration. Use when wiring event-driven business logic, building webhook consumers, or replacing ActiveSupport callback chains.
tools
Cross-cutting Spree development patterns — the customization preference hierarchy (Events > Webhooks > Dependencies > Decorators), `Spree::Dependencies` service-object swapping, the `_decorator.rb` + `prepend` + `self.prepended` idiom, idempotent subscribers and webhook receivers, multi-store scoping discipline, prefixed IDs, calculator polymorphism (shipping/promotion/tax share the base), service-object composition with `dry-monads` or simple results, why to avoid `class_eval` reopening and Deface, and Spree-on-Rails idioms (Hotwire/Turbo Stimulus, ActiveStorage, Action Cable, Sidekiq). Use when designing the architecture of a Spree extension or solving cross-cutting concerns.