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