Skip to content
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 access tokens in token exchange #1822

Merged
merged 3 commits into from
Apr 16, 2024

Conversation

zzooeeyy
Copy link
Contributor

@zzooeeyy zzooeeyy commented Apr 2, 2024

📹 Demo video

What this PR does

  • Handles 401 error in around_action in token exchange concern activate_shopfiy_session.
  • It'll retry once by performing token exchange to retrieve new access token.
  • Subsequent errors will be thrown.
  • Introduces ShopifyApp::Auth::TokenExchange.perform(session_token)
  • Introduces ShopifyApp::AdminAPI::WithTokenRefetch module with a method to allow easy token refetch/retry on Unauthorized errors
with_token_refetch(@session, @shopify_id_token) do
  # Admin API call here
end

So developers handling their own errors can still have their access tokens refetched:

# my_controller.rb

def count_and_rescue
  with_token_refetch(current_shopify_session, shopify_id_token) do
    ShopifyAPI::Product.count
  end
rescue =>
  # performing error handling
end

Checklist

Before submitting the PR, please consider if any of the following are needed:

  • [ will update when token exchange feature is complete ] Update CHANGELOG.md if the changes would impact users
  • [ will update when token exchange feature is complete ] Update README.md, if appropriate.
  • [ will update when token exchange feature is complete ] Update any relevant pages in /docs, if necessary
  • [ will update when token exchange feature is complete ] For security fixes, the Disclosure Policy must be followed.

@zzooeeyy zzooeeyy force-pushed the handle-invalid-access-token branch from f5f33bf to 01c0995 Compare April 3, 2024 17:17
@zzooeeyy zzooeeyy marked this pull request as ready for review April 3, 2024 17:22
@zzooeeyy zzooeeyy requested a review from a team as a code owner April 3, 2024 17:22
@zzooeeyy zzooeeyy changed the title Retrying block if encountered 401 error Handle invalid access tokens in token exchange Apr 3, 2024
@rachel-carvalho
Copy link
Contributor

We'll create an API wrapper and handle errors differently, so I'm moving this back to draft.

@rachel-carvalho rachel-carvalho marked this pull request as draft April 5, 2024 20:08
@rachel-carvalho
Copy link
Contributor

We decided to keep retrying in the around_action, but will also introduce a module ShopifyApp::AdminAPI::WithTokenRefetch that offers a method that will automatically re-fetch an access token on Unauthorized errors and retry the block.

with_token_refetch(@session, @session_token) do
  # Admin API call here
end

@rachel-carvalho rachel-carvalho removed their request for review April 10, 2024 18:43
@rachel-carvalho rachel-carvalho marked this pull request as ready for review April 10, 2024 19:13
@rachel-carvalho rachel-carvalho self-assigned this Apr 10, 2024
Copy link
Contributor Author

@zzooeeyy zzooeeyy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clean up, I just have some questions! ❤️

Copy link
Contributor

@paulomarg paulomarg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is great! We should also make sure to document the new public-facing aspects of these changes - ideally with some examples of how folks might use them.

lib/shopify_app/admin_api/with_token_refetch.rb Outdated Show resolved Hide resolved
lib/shopify_app/admin_api/with_token_refetch.rb Outdated Show resolved Hide resolved
lib/shopify_app/controller_concerns/token_exchange.rb Outdated Show resolved Hide resolved
lib/shopify_app/controller_concerns/token_exchange.rb Outdated Show resolved Hide resolved
test/shopify_app/auth/token_exchange_test.rb Outdated Show resolved Hide resolved
@rachel-carvalho
Copy link
Contributor

The tests that execute the new Session#copy_attributes_from method are now failing until we update the shopify_api version to include it.

@@ -203,6 +204,64 @@ user.with_shopify_session do
end
```

#### Re-fetching an access token when API returns Unauthorized
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this section to the sessions doc to document usage cc @zzooeeyy @paulomarg

Copy link
Contributor Author

@zzooeeyy zzooeeyy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Some more 💭

docs/shopify_app/sessions.md Outdated Show resolved Hide resolved

def index
client = ShopifyAPI::Clients::Graphql::Admin.new(session: current_shopify_session)
with_token_refetch(current_shopify_session, session_token) do # Unauthorized errors raised in this block will initiate token exchange and the block will be retried once
Copy link
Contributor Author

@zzooeeyy zzooeeyy Apr 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm looking at the example here, do you think it might be confusing to devs on the difference between current_shopify_session and session_token? There are so many cases where we just use "session" to describe something, should we rename (in the actual method implementation as well) session_token to be like session_jwt_token to be more explicit on which one we're talking about?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree it's very confusing. I noticed we call it id_token in the URL and also in App Bridge, so I'm leaning towards shopify_id_token here to keep consistence, especially because those are the two sources of the token we're using here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I think that's good, we also use the phrase session token in quite a few places (docs, etc), even though it's really an id token. We'd probably want to be consistent with that, right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was chatting with @ragalie about this to get a better understanding of session token vs ID token, and what I got is that this session token is a type of id token, which is part of the Open ID spec and is supposed to be a claim by the server about a user's identity. session token is Shopify's claim about the current user that's logged in, it's an ID token and it's in JWT format.

I do agree that we need to make it clear that id_token in some places and session_token in others means the same thing, just like session in the context of the libraries usually means access_token.

docs/shopify_app/sessions.md Outdated Show resolved Hide resolved
lib/shopify_app/admin_api/with_token_refetch.rb Outdated Show resolved Hide resolved
Copy link
Contributor

@paulomarg paulomarg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had some nits but looking really good!

docs/shopify_app/sessions.md Outdated Show resolved Hide resolved
docs/shopify_app/sessions.md Outdated Show resolved Hide resolved
docs/shopify_app/sessions.md Outdated Show resolved Hide resolved
test/shopify_app/auth/token_exchange_test.rb Show resolved Hide resolved
Copy link
Contributor

@ragalie ragalie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

Copy link
Contributor

@paulomarg paulomarg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one last nit, non-blocking if it is the case :)

Comment on lines +49 to +50
ShopifyApp::Auth::TokenExchange.perform(shopify_id_token)
# TODO: Rescue JWT validation errors when bounce page is ready
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this TODO also covers requests where no id token is present?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yesss

@rachel-carvalho rachel-carvalho merged commit 94c3ac3 into main Apr 16, 2024
10 checks passed
@rachel-carvalho rachel-carvalho deleted the handle-invalid-access-token branch April 16, 2024 20:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants