-
Notifications
You must be signed in to change notification settings - Fork 125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor oauth strategy #491
Conversation
fea7dc6
to
1231790
Compare
52ce982
to
5abfc1e
Compare
d1f6e4b
to
c6ac503
Compare
packages/shopify-app-remix/src/server/authenticate/admin/__tests__/doc-request-path.test.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can remove this test, if we're okay with keeping auth-callback-path.test.ts
and auth-path.test.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As messaged on Slack i'd like to step through through these changes together on tuple to understand them a bit more. Without that high speed back n forth it's quite a lot to understand and quite hard to do the review justice
Adding a mini review now, but let's chat before actioning anything here
'@shopify/shopify-app-remix': minor | ||
--- | ||
|
||
Refactor AuthStrategy to extract OAuth authorization code flow behaviour into a separate class. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since partners won't care about this, I'm not sure if this needs a release note? Thoughts @paulomarg
|
||
return this.validateAuthenticatedSession(request, sessionToken); | ||
} else { | ||
if (!sessionTokenHeader) { | ||
await this.validateUrlParams(request); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both the session token and the URL params expire and can only be generated using the API secret. Given that, does token exchange need to validateURL Params?
const {config, logger, api} = this; | ||
const url = new URL(request.url); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this is path specific logic is really scattered and difficult to see all the routes we handle, and this url parsing is repeated too many times throughout this common handleRoutes
logic and the strategy specific handleRoutes
logic.
Just throwing some ideas:
- Would it benefit from using a switch statement so that we can see from a glance all the routes we handle
private async handleRoutes(request: Request) {
const {config, logger, api} = this;
const url = new URL(request.url);
switch(url.pathname) {
case config.auth.patchSessionTokenPath:
logger.debug('Rendering bounce page');
throw renderAppBridge({config, logger, api}, request);
case config.auth.exitIframePath:
const destination = url.searchParams.get('exitIframe')!;
logger.debug('Rendering exit iframe page', {destination});
throw renderAppBridge({config, logger, api}, request, {url: destination});
....
etc
}
}
- If we do what Richard suggested here
the handleRoutes logic can be in the common class so that:
// ******* Common Class
private async handleRoutes(request: Request) {
const {config, logger, api} = this;
const url = new URL(request.url);
switch(url.pathname) {
case config.auth.patchSessionTokenPath:
logger.debug('Rendering bounce page');
throw renderAppBridge({config, logger, api}, request);
case config.auth.exitIframePath:
const destination = url.searchParams.get('exitIframe')!;
logger.debug('Rendering exit iframe page', {destination});
throw renderAppBridge({config, logger, api}, request, {url: destination});
....
etc
}
}
// ********** Auth strategy specific class:
private async handleRoutes(request: Request) {
const {config, logger, api} = this;
const url = new URL(request.url);
switch(url.pathname) {
case config.auth.path:
throw await this.handleAuthBeginRequest(request, shop)
case config.auth.callbackPath:
throw await this.handleAuthCallbackRequest(request, shop)
default :
// Call common class's method `handleRoutes` to handle "patchSessionTokenPath" & "exitIframePath" by default
....
etc
}
}
const isEmbedded = url.searchParams.get('embedded') === '1'; | ||
|
||
if (!offlineSession) { | ||
logger.info("Shop hasn't installed app yet, redirecting to OAuth", { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This log displays for people using online tokens it's a bit of a misnomer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should happen in both cases - using online tokens causes OAuth to create both offline and online, and we use the presence of the offline token as indication that the app was installed (because it doesn't expire).
fa92983
to
62e6a1a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, I had a bunch of nits but none were blocking.
packages/shopify-app-remix/src/server/authenticate/admin/authenticate.ts
Outdated
Show resolved
Hide resolved
packages/shopify-app-remix/src/server/authenticate/admin/__tests__/doc-request-path.test.ts
Show resolved
Hide resolved
packages/shopify-app-remix/src/server/authenticate/admin/authenticate.ts
Outdated
Show resolved
Hide resolved
packages/shopify-app-remix/src/server/authenticate/admin/authenticate.ts
Show resolved
Hide resolved
const isEmbedded = url.searchParams.get('embedded') === '1'; | ||
|
||
if (!offlineSession) { | ||
logger.info("Shop hasn't installed app yet, redirecting to OAuth", { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should happen in both cases - using online tokens causes OAuth to create both offline and online, and we use the presence of the offline token as indication that the app was installed (because it doesn't expire).
packages/shopify-app-remix/src/server/authenticate/admin/strategies/auth-code-flow.ts
Outdated
Show resolved
Hide resolved
packages/shopify-app-remix/src/server/authenticate/admin/strategies/auth-code-flow.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like having these in the same file, but the file name is technically wrong now 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed that renaming will bring about changes to a bunch of new files. For that reason, let's just do that as part of another PR? Given how big this one is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah no problem
d90c52d
to
36009f5
Compare
36009f5
to
887eb77
Compare
Add AuthorizationStrategy interface to ensure proper class types
… functionality for authenticate is not complex enough for a Class, and just adds more ceremony
Co-authored-by: Paulo Margarido <[email protected]> Co-authored-by: Rezaan Syed <[email protected]>
887eb77
to
2aa5ad4
Compare
WHY are these changes introduced?
Part of https://github.com/Shopify/develop-app-access/issues/134
This change enables us to add token exchange in a following PR. This does not change any behaviour to the current OAuth authorization code flow. It is simply a refactor of the
AuthStrategy
class.WHAT is this pull request doing?
AuthCodeFlowStrategy
class, which is injected into theAuthStrategy
class.Type of change
Checklist
yarn changeset
to create a draft changelog entry (do NOT update theCHANGELOG.md
files manually)