[Shopify] Migrate Shopify Connector to Expiring Offline Access Tokens#9327
Draft
onbuyuka wants to merge 5 commits into
Draft
[Shopify] Migrate Shopify Connector to Expiring Offline Access Tokens#9327onbuyuka wants to merge 5 commits into
onbuyuka wants to merge 5 commits into
Conversation
Adds support for Shopify expiring offline access tokens (public apps must
migrate by 2027-01-01):
- Persist token/refresh expiry on "Shpfy Registered Store New" and store the
refresh token in IsolatedStorage.
- Request expiring tokens on install (expiring=1), refresh before expiry, and
migrate legacy non-expiring tokens via token exchange (best-effort).
- Orchestrate on-demand from "Shpfy Communication Mgt." (GetAccessToken) with a
reactive 401 refresh-and-retry.
- Scheduled backstop job ("Shpfy Token Refresh" + per-shop worker) to keep
tokens and 90-day refresh tokens alive; registered via installer/upgrade.
- Shop Card reconnect notification when the refresh token has expired.
- Tests for the refresh-token expiry decision logic.
NOTE: "Shpfy Token Dev Tools" (page 30440) is temporary test scaffolding and
must be removed before merge.
Fixes AB#637954
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5fe0c18c-7f03-4f1f-880f-9adb9eb1dfcc
- Remove the temporary "Shpfy Token Dev Tools" page (30440) and its permission-set entry. - Clear the new telemetry event IDs (set to '') so they can be assigned by the tagging script. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5fe0c18c-7f03-4f1f-880f-9adb9eb1dfcc
Refresh the living docs (al-docs update) to cover slice 637954: - business-logic.md: new "Authentication and token lifecycle" section. - data-model.md: Shpfy Registered Store New token/expiry storage + ER entry. - patterns.md: Job Queue dispatcher/worker per-shop isolation pattern. - CLAUDE.md (app + Base): auth overview and "things to know". Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5fe0c18c-7f03-4f1f-880f-9adb9eb1dfcc
Remove the LogTokenTelemetry helper and inline Session.LogMessage('', ...) at
each call site so the telemetry tagging script can assign event IDs (it only
fills literal Session.LogMessage first-args). Matches the existing connector
convention. Tags left empty pending the script.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5fe0c18c-7f03-4f1f-880f-9adb9eb1dfcc
Fill the token lifecycle telemetry event IDs (0000UIV-0000UJ1) via the tagging script. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5fe0c18c-7f03-4f1f-880f-9adb9eb1dfcc
AndreiPanko
reviewed
Jul 11, 2026
| end; | ||
|
|
||
| local procedure SaveStoreInfo(Store: Text; ActualScope: Text; AccessToken: SecretText) | ||
| local procedure SaveInstalledToken(Store: Text; ResponseBody: Text) |
| JobQueueEntry."No. of Minutes between Runs" := 720; | ||
| JobQueueEntry."No. of Attempts to Run" := 5; | ||
| JobQueueEntry.Description := CopyStr(JobDescriptionTxt, 1, MaxStrLen(JobQueueEntry.Description)); | ||
| JobQueueEntry."Job Queue Category Code" := JobQueueCategoryLbl; |
Contributor
There was a problem hiding this comment.
Risk that it will be in the same category as pricing or inventory, which might take 1 hour to complete
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Background
As of December 2025, Shopify supports expiring offline access tokens with refresh-token rotation. Public apps created before 2026-04-01 must migrate to expiring tokens by 2027-01-01; after that date, REST/GraphQL Admin API requests made with non-expiring tokens are rejected. The Shopify Connector currently uses non-expiring offline tokens and must be migrated.
Token characteristics (Shopify):
expires_in: 3600)refresh_token_expires_in: 7776000)Refs: About offline access tokens - Migrating from non-expiring to expiring tokens
Approach
Token validity is centralized in a single orchestrator,
EnsureValidAccessToken(Store), invoked fromShpfy Communication Mgt.GetAccessToken- so every API call (interactive and background) transparently migrates a legacy token or refreshes an expiring one before use. A scheduled backstop job additionally keeps idle shops access/refresh tokens alive and completes migrations for shops that never make an on-demand call.Changes
Token storage -
Shpfy Registered Store New(table 30138)Token Expires At/Refresh Token Expires At; refresh token kept in IsolatedStorage.Acquisition, refresh & migration -
Shpfy Authentication Mgt.(codeunit 30199)expiring=1).EnsureValidAccessTokenorchestrates migrate-if-legacy / refresh-if-near-expiry, serialized per shop.RefreshAccessToken(grant_type=refresh_token) with transient retry and a terminal reconnect error.MigrateToExpiringToken(one-time token exchange, best-effort - keeps the working token on failure).ForceTokenRefresh,IsRefreshTokenExpired, and a Shop Card reconnect notification.Consumption -
Shpfy Communication Mgt.GetAccessTokeninvokes the orchestrator; reactive 401 -> refresh -> retry inExecuteWebRequest.Scheduled backstop -
Shpfy Token Refresh(30431) +Shpfy Token Refresh Shop(30432)TableNo = Job Queue Entry) iterates enabled shops and runs the per-shop worker (TableNo = Shpfy Shop) viaCodeunit.Runfor isolation; recurring Job Queue entry registered via installer + upgrade.UX -
Shpfy Shop CardDocs & tests
Shpfy Token Refresh Testunit tests; living docs refreshed (business-logic, data-model, patterns, CLAUDE.md).Telemetry
Emitted for migration success/failure, refresh success/transient/terminal and backstop per-shop failures, under event IDs
0000UIV-0000UJ1.Test plan
Shpfy Token Refresh Testunit tests for the expiry decisions.Fixes AB#637954