@@ -14,6 +14,7 @@ import { isSameOrigin } from '@/lib/core/utils/validation'
1414import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
1515import { APP_ENTRY_PATH } from '@/lib/navigation/paths'
1616import { completeShopifyOAuthConnection } from '@/lib/oauth/shopify'
17+ import { ShopifyOAuthError } from '@/lib/oauth/shopify-installation'
1718import { parseShopifyOAuthState } from '@/lib/oauth/shopify-state'
1819
1920const logger = createLogger ( 'ShopifyCallback' )
@@ -75,7 +76,7 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
7576 } )
7677
7778 const {
78- values : { SHOPIFY_CLIENT_ID : clientId , SHOPIFY_CLIENT_SECRET : clientSecret } ,
79+ values : { SHOPIFY_CLIENT_SECRET : clientSecret } ,
7980 } = requireConfiguredOAuthClient ( 'shopify' )
8081
8182 if ( ! validateHmac ( searchParams , clientSecret ) ) {
@@ -111,64 +112,31 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
111112 clientSecret,
112113 } )
113114
114- const tokenResponse = await fetch ( `https://${ shopDomain } /admin/oauth/access_token` , {
115- method : 'POST' ,
116- headers : {
117- 'Content-Type' : 'application/json' ,
118- } ,
119- body : JSON . stringify ( {
120- client_id : clientId ,
121- client_secret : clientSecret ,
122- code : code ,
123- } ) ,
124- } )
125-
126- if ( ! tokenResponse . ok ) {
127- const errorText = await tokenResponse . text ( )
128- logger . error ( 'Failed to exchange code for token:' , {
129- status : tokenResponse . status ,
130- body : errorText ,
131- } )
132- return NextResponse . redirect ( `${ baseUrl } ${ APP_ENTRY_PATH } ?error=shopify_token_error` )
133- }
134-
135- const tokenData = await tokenResponse . json ( )
136- const accessToken = tokenData . access_token
137- const scope = tokenData . scope
138-
139- logger . info ( 'Shopify token exchange successful:' , {
140- hasAccessToken : ! ! accessToken ,
141- scope : scope ,
142- } )
143-
144- if ( ! accessToken ) {
145- logger . error ( 'No access token in response' )
146- return NextResponse . redirect ( `${ baseUrl } ${ APP_ENTRY_PATH } ?error=shopify_no_token` )
115+ if ( returnUrl && ! isSameOrigin ( returnUrl ) ) {
116+ throw new Error ( 'Shopify OAuth state contains an invalid return URL' )
147117 }
148118
149119 await completeShopifyOAuthConnection ( {
150- accessToken ,
120+ code ,
151121 shopDomain,
152- scope,
153122 userId : session . user . id ,
154123 draftId,
155124 signal : request . signal ,
156125 } )
157126
158- if ( returnUrl && ! isSameOrigin ( returnUrl ) ) {
159- throw new Error ( 'Shopify OAuth state contains an invalid return URL' )
160- }
161127 const redirectUrl = returnUrl ?? `${ baseUrl } ${ APP_ENTRY_PATH } `
162128 const finalUrl = new URL ( redirectUrl )
163129 finalUrl . searchParams . set ( 'shopify_connected' , 'true' )
164130
165131 return clearShopifyOAuthCookies ( NextResponse . redirect ( finalUrl ) )
166132 } catch ( error ) {
167- logger . error ( 'Error in Shopify OAuth callback:' , error )
133+ logger . error ( 'Shopify OAuth callback failed' )
168134 const errorCode =
169135 error instanceof EnvCapabilityConfigurationError && error . capabilityId === 'oauth'
170136 ? 'shopify_config_error'
171- : 'shopify_callback_error'
137+ : error instanceof ShopifyOAuthError
138+ ? error . callbackError
139+ : 'shopify_callback_error'
172140 return clearShopifyOAuthCookies (
173141 NextResponse . redirect ( `${ baseUrl } ${ APP_ENTRY_PATH } ?error=${ errorCode } ` )
174142 )
0 commit comments