-
Notifications
You must be signed in to change notification settings - Fork 692
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
Handle invalid session token #1823
Conversation
e3e43cf
to
eeb490b
Compare
fadc394
to
815f60a
Compare
815f60a
to
3bcaff0
Compare
659f8a3
to
6ff99df
Compare
6ff99df
to
b65aac4
Compare
if ShopifyApp.configuration.use_new_embedded_auth_strategy? | ||
include ShopifyApp::TokenExchange | ||
include ShopifyApp::EmbeddedApp | ||
around_action :activate_shopify_session |
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 the docs mention EnsureInstalled
provides the installed_shop_session
method and EnsureHasSession
provides current_shopify_session
. I think TokenExchange#activate_shopify_session
provides current_shopify_session
, right? Should it be different for EnsureInstalled
? Or maybe provide both methods?
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.
Yess, so EnsureInstalled
concern itself implements the installed_shop_session method, so it'll still be able to be used. Having TokenExchange enabled, they'll just get both 'current_shopify_sessionand
installed_shop_session` !
retrieve_session_from_token_exchange if current_shopify_session.blank? || should_exchange_expired_token? | ||
begin | ||
retrieve_session_from_token_exchange if current_shopify_session.blank? || should_exchange_expired_token? | ||
rescue *INVALID_SHOPIFY_ID_TOKEN_ERRORS => e |
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.
Could we rescue these errors for the entire activate_shopify_session
method? with_token_refetch
might also end up raising this error, since it performs token exchange.
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 was pairing with Mike and we thought that's not worth it since we already check for validity before we call token exchange, it'd just be adding extra work for the slightest chance that it might expire within that timeframe... There are leeways in-place to ensure we don't encounter these problems..?
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.
Oh but what if we don't perform token exchange there because current_shopify_session
exists and then do during with_token_refetch
? In that case it wouldn't be double validation/rescue, right?
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.
hmmm I think this will cause a "Double render/redirect" error since this is around the controller action.. so if we handle the error and respond with retry or redirect to bounce page and the controller action also renders... 🤔
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.
If the action raises a token exchange error it will likely not have rendered yet, but you're right that it could happen if the app doesn't follow the pattern of rendering/redirecting as the last thing in the action 🤔
I looked up and saw there's a performed?
method we can call in the controller to avoid a double render/redirect. What if we bounce unless performed?
@@ -178,13 +183,48 @@ class TokenExchangeControllerTest < ActionController::TestCase | |||
end | |||
end | |||
|
|||
[ | |||
ShopifyAPI::Errors::InvalidJwtTokenError, | |||
ShopifyAPI::Errors::CookieNotFoundError, |
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.
Maybe we shouldn't respond to invalid cookies with a bounce page now that we'll be using the method that exclusively checks shopify_id_token
.
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.
Yea once I use the new utility method, we won't be handling CookieNotFoundError
error anymore, but it'll be checking for MissingJwtTokenError
instead
expected_redirect_url = "/my-root/patch_shopify_id_token?my_param=for-keeps&shop=my-shop.myshopify.com" | ||
expected_redirect_url += "&shopify-reload=%2Freloaded_path%3Fmy_param%3Dfor-keeps%26shop%3Dmy-shop.myshopify.com" |
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.
Nit: maybe we could URL encode the param for better readability of the test?
expected_redirect_url = "/my-root/patch_shopify_id_token?my_param=for-keeps&shop=my-shop.myshopify.com" | |
expected_redirect_url += "&shopify-reload=%2Freloaded_path%3Fmy_param%3Dfor-keeps%26shop%3Dmy-shop.myshopify.com" | |
reload_url = CGI.escape("/reloaded_path?my_param=for-keeps&shop=#{@shop}") | |
expected_redirect_url = "/my-root/patch_shopify_id_token?my_param=for-keeps&shop=my-shop.myshopify.com&shopify-reload=#{reload_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.
🤯 NICE!
# redirect_to("#{patch_session_token_url}?#{patch_session_token_params.to_query}", allow_other_host: true) | ||
# end | ||
redirect_to( | ||
"#{patch_shopify_id_token_url}?#{patch_shopify_id_token_params.to_query}", |
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 wish there was a way to use the Rails URL helper method patch_shopify_id_token_path
here which already does most of the URL assembly work for us, but the way our tests are setup using with_routing
it's not including engine's routes, so I think it would be a bit too much work for it to be worth it.
@@ -5,8 +5,18 @@ module TokenExchange | |||
extend ActiveSupport::Concern | |||
include ShopifyApp::AdminAPI::WithTokenRefetch | |||
|
|||
INVALID_SHOPIFY_ID_TOKEN_ERRORS = [ | |||
ShopifyAPI::Errors::CookieNotFoundError, |
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.
Would we ever have a cookie present for token exchange? If it's only meant to run for embedded apps there should never be any cookies involved, right?
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.
Yea cookies are never involved.. but the way ShopifyAPI::current_session_id
is setup, it'll throw a "CookieNotFoundError" if we pass in a nil auth header (which will be the case for the initial server load when we're not using id_token from URL params), so once I change this to use the new util method, we won't be catching this CookieNotFoundError
but MissingJwtTokenError
instead.
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.
Hmm that's fair. I guess we can't change this without it potentially breaking apps out there, right?
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.
Yea exactly :(
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.
Looks good to me, thanks Zoey!
What this PR does
Tophatting-
id_token
from URL param yet, so session token will be invalid initially, this redirect shouldn't be hit as often once we are usingid_token
)create
failed from invalid session token, sinceX-Shopify-Retry-Invalid-Session-Request
is set from the response, app bridge will retrycreate
with new session token, thus passing the second timecreate
returns 401 in every other request from my test setup..Checklist
Before submitting the PR, please consider if any of the following are needed:
CHANGELOG.md
if the changes would impact usersREADME.md
, if appropriate./docs
, if necessary