Shopify 在 2026 年 10 月 27 日更新公開 App 的離線 access token 遷移時程。仍使用不會定期到期的 offline token 的既有公開 App,必須改用 expiring offline access token;官方公告列出分階段措施:2027 年 1 月 1 日起不合規 App 會從 App Store 下架並停止接受新安裝,1 月 15 日起受影響商家會在 Shopify Admin 看到警告,4 月 1 日起相關 Admin API 請求會回傳 HTTP 403。
這個要求不是所有 Shopify 整合一體適用。公告明確限定既有公開 App,custom apps 與商家自行建立的 apps 排除;2026 年 4 月 1 日以後建立的公開 App 原本就已受要求約束。Shopify Help Center也將 Dev Dashboard custom app 與舊式 custom app 的 access token 取得方式分開說明。團隊第一步不是全站重做 OAuth,而是依 distribution type、建立日期與目前 session/token 形式盤點真正受影響的安裝。
為什麼背景工作特別容易出問題
Offline token 用於沒有人開著 App 時仍要呼叫 GraphQL Admin API 的情境,例如 webhook handler、訂單同步、庫存排程與報表工作。非到期 token 通常持續有效直到商店移除 App 或憑證被撤銷,一旦外洩,攻擊者能使用的時間也更長。
Shopify 的 expiring token 文件說明,到期型 offline access token 有效時間為一小時,並搭配 refresh token。每次刷新時,Shopify 會輪替 refresh token,因此資料庫不能只覆寫 access token 而忽略新 refresh token,也不能讓同一商店的多個 worker 無協調地同時刷新。
最危險的競態是兩個程序同時取得目前 refresh token,各自交換新 token。若其中一個較晚把舊結果寫回,資料庫可能保留已失效的 refresh token,之後所有背景工作一起失敗。應以 shop_id 或安裝識別建立單一刷新鎖,寫入 access token、refresh token、到期時間與版本時使用同一筆交易,並在衝突時重新讀取最新狀態。
先把 token 狀態從一般 session 中分離
盤點資料模型時,至少需要 store identity、加密後 access token、加密後 refresh token、access expiry、refresh expiry、scope、最後刷新時間與狀態版本。不要把 token 放在日誌、錯誤追蹤標籤、queue payload 或前端;加密金鑰與資料庫權限也要分開管理。
背景 job 不應在入列時複製 access token,因為輪到執行時可能已過期。Queue 只帶 store ID 與業務參數,worker 開始前向集中式 token service 取得可用憑證;若接近到期,由該服務在鎖內刷新,再把當次有效 token 交給 worker。如此可避免大量排程各自實作一套刷新邏輯。
應保留刷新失敗的分類:無效或已輪替 refresh token、權限被撤銷、App 已解除安裝、暫時性網路錯誤、API rate limit 與資料庫寫入衝突。只有暫時性錯誤適合有限次退避重試;若需要商家重新授權,應停止受影響工作、保存待處理游標並提供清楚的恢復流程,不能持續重試到 webhook 或 queue 堆滿。
遷移既有安裝不能只改新安裝設定
在新程式開啟 expiring token 模式,只能確保之後取得的 token 符合新格式,不代表資料庫裡所有既有安裝已遷移。官方遷移指南提供既有安裝的轉換流程;團隊應建立 migration state,逐店記錄 eligible、scheduled、migrated、validated、needs reauth 或 excluded,而不是用一次 SQL 更新假設全部成功。
先在開發商店與內部安裝驗證,再對少量正式商店啟用。每批遷移後,用低風險 GraphQL 查詢確認新 access token、等待至少一次自動刷新、觸發代表性的 webhook 與排程,並確認舊 token 不再被程式讀取。只有完成 token exchange 不算驗收,因為真正風險通常發生在一小時後或多 worker 競爭時。
Shopify 也新增 client credentials access,讓符合條件的公開 App 後端以私鑰簽署短效 client assertion,取得 application-only access token,不必等待商家重開 App。它適合排程與 webhook 等後端工作,但不是把私鑰複製到每台 worker 的理由;應集中簽署、限制金鑰存取、規劃輪替,並確認所需 API 與 distribution 條件符合官方文件。
上線順序要保留舊格式讀取能力
第一階段先部署能同時讀取舊 token 與新 token 欄位的程式,建立 token service、刷新鎖、加密與監控,但還不大量轉換。第二階段讓新安裝與重新授權走 expiring token,觀察刷新成功率與背景 job。第三階段批次遷移既有安裝,控制每批數量並保留暫停開關。
第四階段在確認沒有活躍舊 token 後,移除舊欄位與程式路徑。不要先做不可逆 schema migration,否則發現 refresh 競態時無法安全回滾。回滾也不能只是切回舊程式;新 token 已經輪替後,舊程式若不認得 refresh token,會立刻失去存取能力。因此回滾版本同樣必須能處理新資料模型。
監控至少分成 token refresh、GraphQL 401/403、重新授權、webhook 成功率、queue age 與每店失敗。HTTP 403 不應全部歸咎於這次期限,因為權限、scope、商店狀態也可能造成拒絕;記錄 Shopify request ID、店鋪識別與錯誤類型,才能判斷是遷移問題還是個別安裝狀態。
用三個日期安排營運,而不是等最後一天
Shopify Developer Community 的 FAQ在公告後整理了相同階段時程,也反映開發者對既有 token、通知與執行順序的疑問。1 月 1 日的下架與新安裝封鎖已會影響獲客,不能因為既有 API 到 4 月才全面 403 就延後;1 月 15 日的商家警告也可能增加客服與信任成本。
實務里程碑應倒排:先完成所有安裝盤點與資料模型,再完成測試商店的多輪刷新與故障演練,接著分批遷移並處理例外,最後保留數週觀察與重新授權時間。驗收要包含同時刷新、worker 重啟、資料庫短暫不可用、refresh 成功但寫入失敗、App uninstall/reinstall,以及 scope 變更。
這次變更的重點不是把「永久 token」替換成「每小時 token」而已,而是建立可協調的憑證生命週期。先確認適用範圍,集中刷新與加密儲存,逐店遷移並讓背景工作可恢復,才能同時避開 App Store 下架、商家警告與最終 403,而不在期限前製造新的同步事故。