@shopify/shopify-app-remix 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/build/cjs/server/authenticate/admin/authenticate.js +119 -501
  2. package/build/cjs/server/authenticate/admin/billing/cancel.js +1 -0
  3. package/build/cjs/server/authenticate/admin/billing/request.js +1 -0
  4. package/build/cjs/server/authenticate/admin/billing/require.js +1 -0
  5. package/build/cjs/server/authenticate/admin/helpers/create-admin-api-context.js +18 -0
  6. package/build/cjs/server/authenticate/admin/helpers/ensure-app-is-embedded-if-required.js +27 -0
  7. package/build/cjs/server/authenticate/admin/helpers/ensure-session-token-search-param-if-required.js +25 -0
  8. package/build/cjs/server/authenticate/admin/helpers/redirect-to-bounce-page.js +22 -0
  9. package/build/cjs/server/authenticate/admin/helpers/redirect-to-shopify-or-app-root.js +22 -0
  10. package/build/cjs/server/authenticate/admin/helpers/trigger-after-auth-hook.js +21 -0
  11. package/build/cjs/server/authenticate/admin/helpers/validate-shop-and-host-params.js +32 -0
  12. package/build/cjs/server/authenticate/admin/strategies/auth-code-flow.js +310 -0
  13. package/build/cjs/server/authenticate/helpers/get-session-token-header.js +6 -0
  14. package/build/cjs/server/authenticate/helpers/reject-bot-request.js +2 -2
  15. package/build/cjs/server/authenticate/public/checkout/authenticate.js +1 -1
  16. package/build/cjs/server/authenticate/webhooks/authenticate.js +14 -5
  17. package/build/cjs/server/clients/admin/graphql.js +6 -8
  18. package/build/cjs/server/shopify-app.js +12 -6
  19. package/build/cjs/server/version.js +1 -1
  20. package/build/ts/server/__test-helpers/test-config.d.ts +36 -7
  21. package/build/ts/server/__test-helpers/test-config.d.ts.map +1 -1
  22. package/build/ts/server/__test-helpers/test-config.js +34 -6
  23. package/build/ts/server/__test-helpers/test-config.js.map +1 -1
  24. package/build/ts/server/authenticate/admin/authenticate.d.ts +8 -25
  25. package/build/ts/server/authenticate/admin/authenticate.d.ts.map +1 -1
  26. package/build/ts/server/authenticate/admin/authenticate.js +124 -488
  27. package/build/ts/server/authenticate/admin/authenticate.js.map +1 -1
  28. package/build/ts/server/authenticate/admin/billing/types.d.ts +11 -3
  29. package/build/ts/server/authenticate/admin/billing/types.d.ts.map +1 -1
  30. package/build/ts/server/authenticate/admin/helpers/create-admin-api-context.d.ts +5 -0
  31. package/build/ts/server/authenticate/admin/helpers/create-admin-api-context.d.ts.map +1 -0
  32. package/build/ts/server/authenticate/admin/helpers/create-admin-api-context.js +16 -0
  33. package/build/ts/server/authenticate/admin/helpers/create-admin-api-context.js.map +1 -0
  34. package/build/ts/server/authenticate/admin/helpers/ensure-app-is-embedded-if-required.d.ts +3 -0
  35. package/build/ts/server/authenticate/admin/helpers/ensure-app-is-embedded-if-required.d.ts.map +1 -0
  36. package/build/ts/server/authenticate/admin/helpers/ensure-app-is-embedded-if-required.js +25 -0
  37. package/build/ts/server/authenticate/admin/helpers/ensure-app-is-embedded-if-required.js.map +1 -0
  38. package/build/ts/server/authenticate/admin/helpers/ensure-session-token-search-param-if-required.d.ts +3 -0
  39. package/build/ts/server/authenticate/admin/helpers/ensure-session-token-search-param-if-required.d.ts.map +1 -0
  40. package/build/ts/server/authenticate/admin/helpers/ensure-session-token-search-param-if-required.js +23 -0
  41. package/build/ts/server/authenticate/admin/helpers/ensure-session-token-search-param-if-required.js.map +1 -0
  42. package/build/ts/server/authenticate/admin/helpers/index.d.ts +7 -0
  43. package/build/ts/server/authenticate/admin/helpers/index.d.ts.map +1 -1
  44. package/build/ts/server/authenticate/admin/helpers/index.js +7 -0
  45. package/build/ts/server/authenticate/admin/helpers/index.js.map +1 -1
  46. package/build/ts/server/authenticate/admin/helpers/redirect-to-bounce-page.d.ts +3 -0
  47. package/build/ts/server/authenticate/admin/helpers/redirect-to-bounce-page.d.ts.map +1 -0
  48. package/build/ts/server/authenticate/admin/helpers/redirect-to-bounce-page.js +16 -0
  49. package/build/ts/server/authenticate/admin/helpers/redirect-to-bounce-page.js.map +1 -0
  50. package/build/ts/server/authenticate/admin/helpers/redirect-to-shopify-or-app-root.d.ts +3 -0
  51. package/build/ts/server/authenticate/admin/helpers/redirect-to-shopify-or-app-root.d.ts.map +1 -0
  52. package/build/ts/server/authenticate/admin/helpers/redirect-to-shopify-or-app-root.js +32 -0
  53. package/build/ts/server/authenticate/admin/helpers/redirect-to-shopify-or-app-root.js.map +1 -0
  54. package/build/ts/server/authenticate/admin/helpers/trigger-after-auth-hook.d.ts +4 -0
  55. package/build/ts/server/authenticate/admin/helpers/trigger-after-auth-hook.d.ts.map +1 -0
  56. package/build/ts/server/authenticate/admin/helpers/trigger-after-auth-hook.js +28 -0
  57. package/build/ts/server/authenticate/admin/helpers/trigger-after-auth-hook.js.map +1 -0
  58. package/build/ts/server/authenticate/admin/helpers/validate-shop-and-host-params.d.ts +3 -0
  59. package/build/ts/server/authenticate/admin/helpers/validate-shop-and-host-params.d.ts.map +1 -0
  60. package/build/ts/server/authenticate/admin/helpers/validate-shop-and-host-params.js +26 -0
  61. package/build/ts/server/authenticate/admin/helpers/validate-shop-and-host-params.js.map +1 -0
  62. package/build/ts/server/authenticate/admin/strategies/auth-code-flow.d.ts +22 -0
  63. package/build/ts/server/authenticate/admin/strategies/auth-code-flow.d.ts.map +1 -0
  64. package/build/ts/server/authenticate/admin/strategies/auth-code-flow.js +323 -0
  65. package/build/ts/server/authenticate/admin/strategies/auth-code-flow.js.map +1 -0
  66. package/build/ts/server/authenticate/admin/strategies/types.d.ts +11 -0
  67. package/build/ts/server/authenticate/admin/strategies/types.d.ts.map +1 -0
  68. package/build/ts/server/authenticate/admin/strategies/types.js +3 -0
  69. package/build/ts/server/authenticate/admin/strategies/types.js.map +1 -0
  70. package/build/ts/server/authenticate/admin/types.d.ts +4 -0
  71. package/build/ts/server/authenticate/admin/types.d.ts.map +1 -1
  72. package/build/ts/server/authenticate/helpers/get-session-token-header.d.ts +1 -0
  73. package/build/ts/server/authenticate/helpers/get-session-token-header.d.ts.map +1 -1
  74. package/build/ts/server/authenticate/helpers/get-session-token-header.js +7 -1
  75. package/build/ts/server/authenticate/helpers/get-session-token-header.js.map +1 -1
  76. package/build/ts/server/authenticate/helpers/reject-bot-request.d.ts +1 -1
  77. package/build/ts/server/authenticate/helpers/reject-bot-request.d.ts.map +1 -1
  78. package/build/ts/server/authenticate/helpers/reject-bot-request.js +3 -3
  79. package/build/ts/server/authenticate/helpers/reject-bot-request.js.map +1 -1
  80. package/build/ts/server/authenticate/public/appProxy/authenticate.public.app-proxy.doc.d.ts.map +1 -1
  81. package/build/ts/server/authenticate/public/appProxy/authenticate.public.app-proxy.doc.js +2 -2
  82. package/build/ts/server/authenticate/public/appProxy/authenticate.public.app-proxy.doc.js.map +1 -1
  83. package/build/ts/server/authenticate/public/appProxy/types.d.ts +6 -3
  84. package/build/ts/server/authenticate/public/appProxy/types.d.ts.map +1 -1
  85. package/build/ts/server/authenticate/public/checkout/authenticate.js +1 -1
  86. package/build/ts/server/authenticate/public/checkout/authenticate.js.map +1 -1
  87. package/build/ts/server/authenticate/webhooks/authenticate.d.ts.map +1 -1
  88. package/build/ts/server/authenticate/webhooks/authenticate.js +12 -2
  89. package/build/ts/server/authenticate/webhooks/authenticate.js.map +1 -1
  90. package/build/ts/server/clients/admin/graphql.js +2 -2
  91. package/build/ts/server/clients/admin/graphql.js.map +1 -1
  92. package/build/ts/server/clients/admin/types.d.ts +51 -10
  93. package/build/ts/server/clients/admin/types.d.ts.map +1 -1
  94. package/build/ts/server/clients/storefront/types.d.ts +4 -4
  95. package/build/ts/server/config-types.d.ts +5 -5
  96. package/build/ts/server/config-types.d.ts.map +1 -1
  97. package/build/ts/server/future/flags.d.ts.map +1 -1
  98. package/build/ts/server/shopify-app.d.ts.map +1 -1
  99. package/build/ts/server/shopify-app.js +5 -3
  100. package/build/ts/server/shopify-app.js.map +1 -1
  101. package/build/ts/server/types.d.ts +2 -2
  102. package/build/ts/server/version.d.ts +1 -1
  103. package/build/ts/server/version.js +1 -1
  104. package/package.json +4 -4
@@ -2,9 +2,6 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var serverRuntime = require('@remix-run/server-runtime');
6
- var shopifyApi = require('@shopify/shopify-api');
7
- var factory = require('../../clients/admin/factory.js');
8
5
  var ensureCorsHeaders = require('../helpers/ensure-cors-headers.js');
9
6
  var validateSessionToken = require('../helpers/validate-session-token.js');
10
7
  var getSessionTokenHeader = require('../helpers/get-session-token-header.js');
@@ -13,539 +10,160 @@ var respondToOptionsRequest = require('../helpers/respond-to-options-request.js'
13
10
  var cancel = require('./billing/cancel.js');
14
11
  var require$1 = require('./billing/require.js');
15
12
  var request = require('./billing/request.js');
16
- var beginAuth = require('./helpers/begin-auth.js');
17
- var handleClientError = require('./helpers/handle-client-error.js');
18
- var redirectToAuthPage = require('./helpers/redirect-to-auth-page.js');
19
- var redirectWithExitiframe = require('./helpers/redirect-with-exitiframe.js');
13
+ var createAdminApiContext = require('./helpers/create-admin-api-context.js');
14
+ var ensureAppIsEmbeddedIfRequired = require('./helpers/ensure-app-is-embedded-if-required.js');
15
+ var ensureSessionTokenSearchParamIfRequired = require('./helpers/ensure-session-token-search-param-if-required.js');
16
+ require('@shopify/shopify-api');
17
+ require('@remix-run/server-runtime');
20
18
  var redirect = require('./helpers/redirect.js');
21
19
  var renderAppBridge = require('./helpers/render-app-bridge.js');
20
+ var validateShopAndHostParams = require('./helpers/validate-shop-and-host-params.js');
22
21
 
23
- const SESSION_TOKEN_PARAM = 'id_token';
24
- class AuthStrategy {
25
- constructor({
22
+ function authStrategyFactory({
23
+ strategy,
24
+ ...params
25
+ }) {
26
+ const {
26
27
  api,
27
- config,
28
- logger
29
- }) {
30
- this.api = void 0;
31
- this.config = void 0;
32
- this.logger = void 0;
33
- this.api = api;
34
- this.config = config;
35
- this.logger = logger;
36
- }
37
- async authenticateAdmin(request) {
38
- const {
39
- api,
40
- logger,
41
- config
42
- } = this;
43
- rejectBotRequest.rejectBotRequest({
44
- api,
45
- logger,
46
- config
47
- }, request);
48
- respondToOptionsRequest.respondToOptionsRequest({
49
- api,
50
- logger,
51
- config
52
- }, request);
53
- const cors = ensureCorsHeaders.ensureCORSHeadersFactory({
54
- api,
55
- logger,
56
- config
57
- }, request);
58
- let sessionContext;
59
- try {
60
- sessionContext = await this.authenticateAndGetSessionContext(request);
61
- } catch (errorOrResponse) {
62
- if (errorOrResponse instanceof Response) {
63
- cors(errorOrResponse);
64
- }
65
- throw errorOrResponse;
66
- }
67
- const context = {
68
- admin: this.createAdminApiContext(request, sessionContext.session),
69
- billing: this.createBillingContext(request, sessionContext.session),
70
- session: sessionContext.session,
71
- cors
72
- };
73
- if (config.isEmbeddedApp) {
74
- return {
75
- ...context,
76
- sessionToken: sessionContext.token,
77
- redirect: redirect.redirectFactory({
78
- api,
79
- config,
80
- logger
81
- }, request)
82
- };
83
- } else {
84
- return context;
28
+ logger,
29
+ config
30
+ } = params;
31
+ async function respondToBouncePageRequest(request) {
32
+ const url = new URL(request.url);
33
+ if (url.pathname === config.auth.patchSessionTokenPath) {
34
+ logger.debug('Rendering bounce page');
35
+ throw renderAppBridge.renderAppBridge({
36
+ config,
37
+ logger,
38
+ api
39
+ }, request);
85
40
  }
86
41
  }
87
- async authenticateAndGetSessionContext(request) {
88
- const {
89
- api,
90
- logger,
91
- config
92
- } = this;
93
- const params = {
94
- api,
95
- logger,
96
- config
97
- };
42
+ async function respondToExitIframeRequest(request) {
98
43
  const url = new URL(request.url);
99
- const isPatchSessionToken = url.pathname === config.auth.patchSessionTokenPath;
100
- const isExitIframe = url.pathname === config.auth.exitIframePath;
101
- const isAuthRequest = url.pathname === config.auth.path;
102
- const isAuthCallbackRequest = url.pathname === config.auth.callbackPath;
103
- const sessionTokenHeader = getSessionTokenHeader.getSessionTokenHeader(request);
104
- logger.info('Authenticating admin request');
105
- if (isPatchSessionToken) {
106
- logger.debug('Rendering bounce page');
107
- throw renderAppBridge.renderAppBridge(params, request);
108
- } else if (isExitIframe) {
44
+ if (url.pathname === config.auth.exitIframePath) {
109
45
  const destination = url.searchParams.get('exitIframe');
110
46
  logger.debug('Rendering exit iframe page', {
111
47
  destination
112
48
  });
113
- throw renderAppBridge.renderAppBridge(params, request, {
49
+ throw renderAppBridge.renderAppBridge({
50
+ config,
51
+ logger,
52
+ api
53
+ }, request, {
114
54
  url: destination
115
55
  });
116
- } else if (isAuthCallbackRequest) {
117
- throw await this.handleAuthCallbackRequest(request);
118
- } else if (isAuthRequest) {
119
- throw await this.handleAuthBeginRequest(request);
120
- } else if (sessionTokenHeader) {
121
- const sessionToken = await validateSessionToken.validateSessionToken({
122
- api,
123
- logger,
124
- config
125
- }, sessionTokenHeader);
126
- return this.validateAuthenticatedSession(request, sessionToken);
127
- } else {
128
- await this.validateUrlParams(request);
129
- await this.ensureInstalledOnShop(request);
130
- await this.ensureAppIsEmbeddedIfRequired(request);
131
- await this.ensureSessionTokenSearchParamIfRequired(request);
132
- return this.ensureSessionExists(request);
133
56
  }
134
57
  }
135
- async handleAuthBeginRequest(request) {
136
- const {
137
- api,
138
- config,
139
- logger
140
- } = this;
141
- logger.info('Handling OAuth begin request');
142
- const shop = this.ensureValidShopParam(request);
143
- logger.debug('OAuth request contained valid shop', {
144
- shop
145
- });
146
-
147
- // If we're loading from an iframe, we need to break out of it
148
- if (config.isEmbeddedApp && request.headers.get('Sec-Fetch-Dest') === 'iframe') {
149
- logger.debug('Auth request in iframe detected, exiting iframe', {
150
- shop
151
- });
152
- throw redirectWithExitiframe.redirectWithExitIframe({
58
+ function createContext(request$1, session, sessionToken) {
59
+ const context = {
60
+ admin: createAdminApiContext.createAdminApiContext(request$1, session, {
153
61
  api,
154
- config,
155
- logger
156
- }, request, shop);
62
+ logger,
63
+ config
64
+ }),
65
+ billing: {
66
+ require: require$1.requireBillingFactory(params, request$1, session),
67
+ request: request.requestBillingFactory(params, request$1, session),
68
+ cancel: cancel.cancelBillingFactory(params, request$1, session)
69
+ },
70
+ session,
71
+ cors: ensureCorsHeaders.ensureCORSHeadersFactory(params, request$1)
72
+ };
73
+ if (config.isEmbeddedApp) {
74
+ return {
75
+ ...context,
76
+ sessionToken,
77
+ redirect: redirect.redirectFactory(params, request$1)
78
+ };
157
79
  } else {
158
- throw await beginAuth.beginAuth({
159
- api,
160
- config,
161
- logger
162
- }, request, false, shop);
80
+ return context;
163
81
  }
164
82
  }
165
- async handleAuthCallbackRequest(request) {
166
- const {
167
- api,
168
- config,
169
- logger
170
- } = this;
171
- logger.info('Handling OAuth callback request');
172
- const shop = this.ensureValidShopParam(request);
83
+ return async function authenticateAdmin(request) {
173
84
  try {
174
- const {
175
- session,
176
- headers: responseHeaders
177
- } = await api.auth.callback({
178
- rawRequest: request
179
- });
180
- await config.sessionStorage.storeSession(session);
181
- if (config.useOnlineTokens && !session.isOnline) {
182
- logger.info('Requesting online access token for offline session');
183
- await beginAuth.beginAuth({
184
- api,
185
- config,
186
- logger
187
- }, request, true, shop);
188
- }
189
- if (config.hooks.afterAuth) {
190
- logger.info('Running afterAuth hook');
191
- await config.hooks.afterAuth({
192
- session,
193
- admin: this.createAdminApiContext(request, session)
194
- });
195
- }
196
- throw await this.redirectToShopifyOrAppRoot(request, responseHeaders);
197
- } catch (error) {
198
- if (error instanceof Response) {
199
- throw error;
200
- }
201
- logger.error('Error during OAuth callback', {
202
- error: error.message
203
- });
204
- if (error instanceof shopifyApi.CookieNotFound) {
205
- throw await this.handleAuthBeginRequest(request);
206
- } else if (error instanceof shopifyApi.InvalidHmacError || error instanceof shopifyApi.InvalidOAuthError) {
207
- throw new Response(undefined, {
208
- status: 400,
209
- statusText: 'Invalid OAuth Request'
210
- });
211
- } else {
212
- throw new Response(undefined, {
213
- status: 500,
214
- statusText: 'Internal Server Error'
215
- });
216
- }
217
- }
218
- }
219
- async validateUrlParams(request) {
220
- const {
221
- api,
222
- config,
223
- logger
224
- } = this;
225
- if (config.isEmbeddedApp) {
226
- const url = new URL(request.url);
227
- const shop = api.utils.sanitizeShop(url.searchParams.get('shop'));
228
- if (!shop) {
229
- logger.debug('Missing or invalid shop, redirecting to login path', {
230
- shop
231
- });
232
- throw serverRuntime.redirect(config.auth.loginPath);
233
- }
234
- const host = api.utils.sanitizeHost(url.searchParams.get('host'));
235
- if (!host) {
236
- logger.debug('Invalid host, redirecting to login path', {
237
- host: url.searchParams.get('host')
238
- });
239
- throw serverRuntime.redirect(config.auth.loginPath);
240
- }
241
- }
242
- }
243
- async ensureInstalledOnShop(request) {
244
- const {
245
- api,
246
- config,
247
- logger
248
- } = this;
249
- const url = new URL(request.url);
250
- let shop = url.searchParams.get('shop');
251
- const isEmbedded = url.searchParams.get('embedded') === '1';
85
+ rejectBotRequest.respondToBotRequest(params, request);
86
+ respondToOptionsRequest.respondToOptionsRequest(params, request);
87
+ await respondToBouncePageRequest(request);
88
+ await respondToExitIframeRequest(request);
89
+ await strategy.respondToOAuthRequests(request);
252
90
 
253
- // Ensure app is installed
254
- logger.debug('Ensuring app is installed on shop', {
255
- shop
256
- });
257
- const offlineId = shop ? api.session.getOfflineId(shop) : await api.session.getCurrentId({
258
- isOnline: false,
259
- rawRequest: request
260
- });
261
- if (!offlineId) {
262
- logger.info("Could not find a shop, can't authenticate request");
263
- throw new Response(undefined, {
264
- status: 400,
265
- statusText: 'Bad Request'
266
- });
267
- }
268
- const offlineSession = await config.sessionStorage.loadSession(offlineId);
269
- if (!offlineSession) {
270
- logger.info("Shop hasn't installed app yet, redirecting to OAuth", {
271
- shop
272
- });
273
- if (isEmbedded) {
274
- redirectWithExitiframe.redirectWithExitIframe({
275
- api,
276
- config,
277
- logger
278
- }, request, shop);
279
- } else {
280
- throw await beginAuth.beginAuth({
281
- api,
282
- config,
283
- logger
284
- }, request, false, shop);
91
+ // If this is a valid request, but it doesn't have a session token header, this is a document request. We need to
92
+ // ensure we're embedded if needed and we have the information needed to load the session.
93
+ if (!getSessionTokenHeader.getSessionTokenHeader(request)) {
94
+ validateShopAndHostParams.validateShopAndHostParams(params, request);
95
+ await ensureAppIsEmbeddedIfRequired.ensureAppIsEmbeddedIfRequired(params, request);
96
+ await ensureSessionTokenSearchParamIfRequired.ensureSessionTokenSearchParamIfRequired(params, request);
285
97
  }
286
- }
287
- shop = shop || offlineSession.shop;
288
- if (config.isEmbeddedApp && !isEmbedded) {
289
- try {
290
- logger.debug('Ensuring offline session is valid before embedding', {
291
- shop
292
- });
293
- await this.testSession(offlineSession);
294
- logger.debug('Offline session is still valid, embedding app', {
295
- shop
296
- });
297
- } catch (error) {
298
- if (error instanceof shopifyApi.HttpResponseError) {
299
- if (error.response.code === 401) {
300
- logger.info('Shop session is no longer valid, redirecting to OAuth', {
301
- shop
302
- });
303
- throw await beginAuth.beginAuth({
304
- api,
305
- config,
306
- logger
307
- }, request, false, shop);
308
- } else {
309
- const message = JSON.stringify(error.response.body, null, 2);
310
- logger.error(`Unexpected error during session validation: ${message}`, {
311
- shop
312
- });
313
- throw new Response(undefined, {
314
- status: error.response.code,
315
- statusText: error.response.statusText
316
- });
317
- }
318
- } else if (error instanceof shopifyApi.GraphqlQueryError) {
319
- const context = {
320
- shop
321
- };
322
- if (error.response) {
323
- context.response = JSON.stringify(error.response);
324
- }
325
- logger.error(`Unexpected error during session validation: ${error.message}`, context);
326
- throw new Response(undefined, {
327
- status: 500,
328
- statusText: 'Internal Server Error'
329
- });
330
- }
331
- }
332
- }
333
- }
334
- async testSession(session) {
335
- const {
336
- api
337
- } = this;
338
- const client = new api.clients.Graphql({
339
- session
340
- });
341
- await client.query({
342
- data: `#graphql
343
- query shopifyAppShopName {
344
- shop {
345
- name
346
- }
347
- }
348
- `
349
- });
350
- }
351
- ensureValidShopParam(request) {
352
- const url = new URL(request.url);
353
- const {
354
- api
355
- } = this;
356
- const shop = api.utils.sanitizeShop(url.searchParams.get('shop'));
357
- if (!shop) {
358
- throw new Response('Shop param is invalid', {
359
- status: 400
360
- });
361
- }
362
- return shop;
363
- }
364
- async ensureAppIsEmbeddedIfRequired(request) {
365
- const {
366
- api,
367
- logger
368
- } = this;
369
- const url = new URL(request.url);
370
- const shop = url.searchParams.get('shop');
371
- if (api.config.isEmbeddedApp && url.searchParams.get('embedded') !== '1') {
372
- logger.debug('App is not embedded, redirecting to Shopify', {
373
- shop
374
- });
375
- await this.redirectToShopifyOrAppRoot(request);
376
- }
377
- }
378
- async ensureSessionTokenSearchParamIfRequired(request) {
379
- const {
380
- api,
381
- logger
382
- } = this;
383
- const url = new URL(request.url);
384
- const shop = url.searchParams.get('shop');
385
- const searchParamSessionToken = url.searchParams.get(SESSION_TOKEN_PARAM);
386
- if (api.config.isEmbeddedApp && !searchParamSessionToken) {
387
- logger.debug('Missing session token in search params, going to bounce page', {
388
- shop
389
- });
390
- this.redirectToBouncePage(url);
391
- }
392
- }
393
- async ensureSessionExists(request) {
394
- const {
395
- api,
396
- config,
397
- logger
398
- } = this;
399
- const url = new URL(request.url);
400
- const shop = url.searchParams.get('shop');
401
- const searchParamSessionToken = url.searchParams.get(SESSION_TOKEN_PARAM);
402
- if (api.config.isEmbeddedApp) {
403
- logger.debug('Session token is present in query params, validating session', {
404
- shop
98
+ logger.info('Authenticating admin request');
99
+ const {
100
+ payload,
101
+ shop,
102
+ sessionId
103
+ } = await getSessionTokenContext(params, request);
104
+ logger.debug('Loading session from storage', {
105
+ sessionId
405
106
  });
406
- const sessionToken = await validateSessionToken.validateSessionToken({
407
- api,
408
- config,
409
- logger
410
- }, searchParamSessionToken);
411
- return this.validateAuthenticatedSession(request, sessionToken);
412
- } else {
413
- // eslint-disable-next-line no-warning-comments
414
- // TODO move this check into loadSession once we add support for it in the library
415
- // https://github.com/orgs/Shopify/projects/6899/views/1?pane=issue&itemId=28378114
416
- const sessionId = await api.session.getCurrentId({
417
- isOnline: config.useOnlineTokens,
418
- rawRequest: request
107
+ const existingSession = sessionId ? await config.sessionStorage.loadSession(sessionId) : undefined;
108
+ const session = await strategy.authenticate(request, existingSession, shop);
109
+ logger.debug('Request is valid, loaded session from session token', {
110
+ shop: session.shop,
111
+ isOnline: session.isOnline
419
112
  });
420
- if (!sessionId) {
421
- logger.debug('Session id not found in cookies, redirecting to OAuth', {
422
- shop
423
- });
424
- throw await beginAuth.beginAuth({
425
- api,
426
- config,
427
- logger
428
- }, request, false, shop);
113
+ return createContext(request, session, payload);
114
+ } catch (errorOrResponse) {
115
+ if (errorOrResponse instanceof Response) {
116
+ ensureCorsHeaders.ensureCORSHeadersFactory(params, request)(errorOrResponse);
429
117
  }
430
- return {
431
- session: await this.loadSession(request, shop, sessionId)
432
- };
118
+ throw errorOrResponse;
433
119
  }
434
- }
435
- async validateAuthenticatedSession(request, payload) {
436
- const {
120
+ };
121
+ }
122
+ async function getSessionTokenContext(params, request) {
123
+ const {
124
+ api,
125
+ config,
126
+ logger
127
+ } = params;
128
+ const headerSessionToken = getSessionTokenHeader.getSessionTokenHeader(request);
129
+ const searchParamSessionToken = getSessionTokenHeader.getSessionTokenFromUrlParam(request);
130
+ const sessionToken = headerSessionToken || searchParamSessionToken;
131
+ logger.debug('Attempting to authenticate session token', {
132
+ sessionToken: {
133
+ header: headerSessionToken,
134
+ search: searchParamSessionToken
135
+ }
136
+ });
137
+ if (config.isEmbeddedApp) {
138
+ const payload = await validateSessionToken.validateSessionToken({
437
139
  config,
438
140
  logger,
439
141
  api
440
- } = this;
142
+ }, sessionToken);
441
143
  const dest = new URL(payload.dest);
442
144
  const shop = dest.hostname;
443
- const sessionId = config.useOnlineTokens ? api.session.getJwtSessionId(shop, payload.sub) : api.session.getOfflineId(shop);
444
- const session = await this.loadSession(request, shop, sessionId);
445
- logger.debug('Found session, request is valid', {
446
- shop
145
+ logger.debug('Session token is valid', {
146
+ shop,
147
+ payload
447
148
  });
149
+ const sessionId = config.useOnlineTokens ? api.session.getJwtSessionId(shop, payload.sub) : api.session.getOfflineId(shop);
448
150
  return {
449
- session,
450
- token: payload
451
- };
452
- }
453
- async loadSession(request, shop, sessionId) {
454
- const {
455
- api,
456
- config,
457
- logger
458
- } = this;
459
- logger.debug('Loading session from storage', {
151
+ shop,
152
+ payload,
460
153
  sessionId
461
- });
462
- const session = await config.sessionStorage.loadSession(sessionId);
463
- if (!session) {
464
- logger.debug('No session found, redirecting to OAuth', {
465
- shop
466
- });
467
- await redirectToAuthPage.redirectToAuthPage({
468
- api,
469
- config,
470
- logger
471
- }, request, shop);
472
- } else if (!session.isActive(config.scopes)) {
473
- logger.debug('Found a session, but it has expired, redirecting to OAuth', {
474
- shop
475
- });
476
- await redirectToAuthPage.redirectToAuthPage({
477
- api,
478
- config,
479
- logger
480
- }, request, shop);
481
- }
482
- return session;
483
- }
484
- async redirectToShopifyOrAppRoot(request, responseHeaders) {
485
- const {
486
- api
487
- } = this;
488
- const url = new URL(request.url);
489
- const host = api.utils.sanitizeHost(url.searchParams.get('host'));
490
- const shop = api.utils.sanitizeShop(url.searchParams.get('shop'));
491
- const redirectUrl = api.config.isEmbeddedApp ? await api.auth.getEmbeddedAppUrl({
492
- rawRequest: request
493
- }) : `/?shop=${shop}&host=${encodeURIComponent(host)}`;
494
- throw serverRuntime.redirect(redirectUrl, {
495
- headers: responseHeaders
496
- });
497
- }
498
- redirectToBouncePage(url) {
499
- const {
500
- config
501
- } = this;
502
-
503
- // Make sure we always point to the configured app URL so it also works behind reverse proxies (that alter the Host
504
- // header).
505
- url.searchParams.set('shopify-reload', `${config.appUrl}${url.pathname}${url.search}`);
506
-
507
- // eslint-disable-next-line no-warning-comments
508
- // TODO Make sure this works on chrome without a tunnel (weird HTTPS redirect issue)
509
- // https://github.com/orgs/Shopify/projects/6899/views/1?pane=issue&itemId=28376650
510
- throw serverRuntime.redirect(`${config.auth.patchSessionTokenPath}${url.search}`);
511
- }
512
- createBillingContext(request$1, session) {
513
- const {
514
- api,
515
- logger,
516
- config
517
- } = this;
518
- return {
519
- require: require$1.requireBillingFactory({
520
- api,
521
- logger,
522
- config
523
- }, request$1, session),
524
- request: request.requestBillingFactory({
525
- api,
526
- logger,
527
- config
528
- }, request$1, session),
529
- cancel: cancel.cancelBillingFactory({
530
- api,
531
- logger,
532
- config
533
- }, request$1, session)
534
154
  };
535
155
  }
536
- createAdminApiContext(request, session) {
537
- return factory.adminClientFactory({
538
- session,
539
- params: {
540
- api: this.api,
541
- config: this.config,
542
- logger: this.logger
543
- },
544
- handleClientError: handleClientError.handleClientErrorFactory({
545
- request
546
- })
547
- });
548
- }
156
+ const url = new URL(request.url);
157
+ const shop = url.searchParams.get('shop');
158
+ const sessionId = await api.session.getCurrentId({
159
+ isOnline: config.useOnlineTokens,
160
+ rawRequest: request
161
+ });
162
+ return {
163
+ shop,
164
+ sessionId,
165
+ payload: undefined
166
+ };
549
167
  }
550
168
 
551
- exports.AuthStrategy = AuthStrategy;
169
+ exports.authStrategyFactory = authStrategyFactory;
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var shopifyApi = require('@shopify/shopify-api');
6
+ require('@shopify/shopify-api/runtime');
6
7
  var redirectToAuthPage = require('../helpers/redirect-to-auth-page.js');
7
8
  require('@remix-run/server-runtime');
8
9
 
@@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var shopifyApi = require('@shopify/shopify-api');
6
6
  var serverRuntime = require('@remix-run/server-runtime');
7
+ require('@shopify/shopify-api/runtime');
7
8
  var redirectToAuthPage = require('../helpers/redirect-to-auth-page.js');
8
9
  var redirectWithAppBridgeHeaders = require('../helpers/redirect-with-app-bridge-headers.js');
9
10
 
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var shopifyApi = require('@shopify/shopify-api');
6
+ require('@shopify/shopify-api/runtime');
6
7
  var redirectToAuthPage = require('../helpers/redirect-to-auth-page.js');
7
8
  require('@remix-run/server-runtime');
8
9