Expiring offline access tokens explicitly disabled
Verifies React Router expiring offline-token configuration and refresh-metadata storage compatibility.
| Detail | Value |
|---|---|
| Check ID | EXPIRING_OFFLINE_TOKEN |
| Severity | Medium |
| How it runs | Deterministic scan and agent review |
Anchor to Vulnerable exampleVulnerable example
app/shopify.server.ts
import { shopifyApp } from "@shopify/shopify-app-react-router/server";
const shopify = shopifyApp({
// Turning this off keeps long-lived offline tokens that never
// rotate, so a leaked token stays valid until someone notices.
future: { expiringOfflineAccessTokens: false },
sessionStorage: new PrismaSessionStorage(prisma),
});
Anchor to How to fixHow to fix
Enable expiringOfflineAccessTokens and ensure session storage persists expiry and refresh metadata.
For more detail, see Migrate to expiring offline access tokens. Public apps that still use non-expiring offline tokens are delisted and blocked from new installs on January 1, 2027, and their GraphQL Admin API requests are rejected from April 1, 2027.
app/shopify.server.ts
import { shopifyApp } from "@shopify/shopify-app-react-router/server";
const shopify = shopifyApp({
future: { expiringOfflineAccessTokens: true },
sessionStorage: new PrismaSessionStorage(prisma),
});
// Session storage has to persist the refresh metadata, or the
// tokens expire with nothing to renew them.
//
// // prisma/schema.prisma
// model Session {
// expires DateTime?
// refreshToken String?
// refreshTokenExpires DateTime?
// }
- Use expiring offline access tokens, the best practice that this check supports
shopify app security check, the command that runs this check- All app security checks
Was this page helpful?