From 11b6acd674a2cc62a8bfaf43b79054edc1ed95b6 Mon Sep 17 00:00:00 2001 From: River Date: Mon, 13 Apr 2026 20:08:23 +0000 Subject: [PATCH 1/2] Redesign store auth callback page to match Identity UI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adapt the OAuth callback page served during `shopify store auth` to match the visual design of accounts.shopify.com/activate (Shopify Identity's device authorization flow). Changes: - Dark background with radial gradient matching Identity login pages - Shopify bag icon SVG centered above the card (same asset as Identity) - White card with 24px border-radius, 40px padding, and Identity's exact box-shadow treatment - Typography matching Identity: 24px/600 heading, 14px subdued body - Vertically centered layout with fixed "Shopify CLI" footer - Fully self-contained — no external CSS, fonts, or CDN dependencies The page is served from localhost during the PKCE OAuth flow, so all styles and assets must be inline. The Shopify bag SVG is the same one used by accounts.shopify.com/activate. Co-authored-by: Phil McClelland --- .../src/cli/services/store/auth/callback.ts | 86 +++++++++++++++++-- 1 file changed, 79 insertions(+), 7 deletions(-) diff --git a/packages/store/src/cli/services/store/auth/callback.ts b/packages/store/src/cli/services/store/auth/callback.ts index 4e3735da45..e5d86b313c 100644 --- a/packages/store/src/cli/services/store/auth/callback.ts +++ b/packages/store/src/cli/services/store/auth/callback.ts @@ -18,20 +18,92 @@ function renderAuthCallbackPage(title: string, message: string): string { const safeTitle = title.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"') const safeMessage = message.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"') + // Shopify bag icon SVG — same asset used by accounts.shopify.com/activate + const shopifyLogo = `` + return ` ${safeTitle} + - -
-
-

${safeTitle}

-

${safeMessage}

-
-
+ +
+
${shopifyLogo}
+
+

${safeTitle}

+

${safeMessage}

+
+
+
Shopify CLI
` } From cf966e2cff069d05c597cf3865ac525cbe29e0b1 Mon Sep 17 00:00:00 2001 From: Phil McClelland Date: Fri, 17 Apr 2026 10:17:13 -0400 Subject: [PATCH 2/2] Remove footer and clean up copy - Remove "Shopify CLI" footer (unnecessary, caused fixed-position overlap on short viewports) - Use contractions in error messages per CLI design guidelines - Drop trailing periods on single-sentence copy - Tighten success message to imperative form Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/cli/services/store/auth/callback.ts | 23 ++++--------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/packages/store/src/cli/services/store/auth/callback.ts b/packages/store/src/cli/services/store/auth/callback.ts index e5d86b313c..a94d8d39e4 100644 --- a/packages/store/src/cli/services/store/auth/callback.ts +++ b/packages/store/src/cli/services/store/auth/callback.ts @@ -79,20 +79,6 @@ function renderAuthCallbackPage(title: string, message: string): string { line-height: 20px; color: rgb(109, 113, 117); } - .footer { - position: fixed; - bottom: 0; - left: 0; - right: 0; - display: flex; - align-items: center; - justify-content: center; - padding: 16px 20px; - font-size: 12px; - line-height: 16px; - color: rgb(191, 199, 200); - text-align: center; - } @@ -103,7 +89,6 @@ function renderAuthCallbackPage(title: string, message: string): string {

${safeMessage}

- ` } @@ -150,7 +135,7 @@ export async function waitForStoreAuthCode({ outputDebug(outputContent`Received OAuth callback for shop ${outputToken.raw(returnedStore ?? 'unknown')}`) if (!returnedStore) { - fail('OAuth callback store does not match the requested store.') + fail('OAuth callback store doesn\'t match the requested store') return } @@ -162,7 +147,7 @@ export async function waitForStoreAuthCode({ const returnedState = searchParams.get('state') if (!returnedState || !constantTimeEqual(returnedState, state)) { - fail('OAuth callback state does not match the original request.') + fail('OAuth callback state doesn\'t match the original request') return } @@ -174,7 +159,7 @@ export async function waitForStoreAuthCode({ const code = searchParams.get('code') if (!code) { - fail('OAuth callback did not include an authorization code.') + fail('OAuth callback didn\'t include an authorization code') return } @@ -185,7 +170,7 @@ export async function waitForStoreAuthCode({ res.setHeader('Connection', 'close') res.once('finish', () => settle(() => resolve(code))) res.end( - renderAuthCallbackPage('Authentication succeeded', 'You can close this window and return to the terminal.'), + renderAuthCallbackPage('Authentication succeeded', 'Close this window and return to the terminal'), ) })