Skip to content

Commit

Permalink
Accept 'id_token' or 'Bearer id_token' format in SessionUtils::curren…
Browse files Browse the repository at this point in the history
…t_session_id
  • Loading branch information
zzooeeyy committed Apr 18, 2024
1 parent b7c9881 commit 27de2f3
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 33 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ Note: For changes to the API, see https://shopify.dev/changelog?filter=api

## Unreleased
- [#1312](https://github.com/Shopify/shopify-api-ruby/pull/1312) Use same leeway for `exp` and `nbf` when parsing JWT
- [#1314](https://github.com/Shopify/shopify-api-ruby/pull/1314) Add new session util method `SessionUtils::session_id_from_shopify_id_token`
- [#1314](https://github.com/Shopify/shopify-api-ruby/pull/1314)
- Add new session util method `SessionUtils::session_id_from_shopify_id_token`
- `SessionUtils::current_session_id` now accepts shopify Id token in the format of `Bearer this_token` or just `this_token`

## 14.2.0
- [#1309](https://github.com/Shopify/shopify-api-ruby/pull/1309) Add `Session#copy_attributes_from` method
Expand Down
15 changes: 9 additions & 6 deletions docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,17 @@ If your app uses client side rendering instead of server side rendering, you wil

For *embedded* apps:

If you have an `HTTP_AUTHORIZATION` header, you can pass the auth header into:
- `ShopifyAPI::Utils::SessionUtils.current_session_id(auth_header, nil, true)` for online (user) sessions or
- `ShopifyAPI::Utils::SessionUtils.current_session_id(auth_header, nil, false)` for offline (store) sessions.
If you have an `HTTP_AUTHORIZATION` header or `id_token` from the request URL params , you can pass that as `shopify_id_token` into:
- `ShopifyAPI::Utils::SessionUtils.current_session_id(shopify_id_token, nil, true)` for online (user) sessions or
- `ShopifyAPI::Utils::SessionUtils.current_session_id(shopify_id_token, nil, false)` for offline (store) sessions.

You can also use `id_token` from the request URL params to get the session ID:
- `ShopifyAPI::Utils::SessionUtils::session_id_from_shopify_id_token(id_token: id_token_from_param, online: true)` for online (user) sessions or
- `ShopifyAPI::Utils::SessionUtils::session_id_from_shopify_id_token(id_token: id_token_from_param, online: false)` for offline (store) sessions.
`current_session_id` accepts shopify_id_token in the format of `Bearer this_token` or just `this_token`.

You can also use this method to get session ID:
- `ShopifyAPI::Utils::SessionUtils::session_id_from_shopify_id_token(id_token: id_token, online: true)` for online (user) sessions or
- `ShopifyAPI::Utils::SessionUtils::session_id_from_shopify_id_token(id_token: id_token, online: false)` for offline (store) sessions.

`session_id_from_shopify_id_token` does **NOT** accept shopify_id_token in the format of `Bearer this_token`, you must pass in `this_token`.

#### Start Making Authenticated Shopify Requests

Expand Down
17 changes: 6 additions & 11 deletions lib/shopify_api/utils/session_utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,16 @@ class << self

sig do
params(
auth_header: T.nilable(String),
shopify_id_token: T.nilable(String),
cookies: T.nilable(T::Hash[String, String]),
online: T::Boolean,
).returns(T.nilable(String))
end
def current_session_id(auth_header, cookies, online)
def current_session_id(shopify_id_token, cookies, online)
if Context.embedded?
if auth_header
matches = auth_header.match(/^Bearer (.+)$/)
unless matches
ShopifyAPI::Logger.warn("Missing Bearer token in authorization header")
raise Errors::MissingJwtTokenError, "Missing Bearer token in authorization header"
end

session_id_from_shopify_id_token(id_token: T.must(matches[1]), online: online)
if shopify_id_token
id_token = shopify_id_token.gsub("Bearer ", "")
session_id_from_shopify_id_token(id_token: id_token, online: online)
else
# falling back to session cookie
raise Errors::CookieNotFoundError, "JWT token or Session cookie not found for app" unless
Expand All @@ -48,7 +43,7 @@ def current_session_id(auth_header, cookies, online)
).returns(String)
end
def session_id_from_shopify_id_token(id_token:, online:)
raise Errors::MissingJwtTokenError, "Missing Shopify ID Token" unless id_token
raise Errors::MissingJwtTokenError, "Missing Shopify ID Token" if id_token.nil? || id_token.empty?

payload = Auth::JwtPayload.new(id_token)
shop = payload.shop
Expand Down
50 changes: 35 additions & 15 deletions test/utils/session_utils_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,20 @@ def setup

@jwt_token = JWT.encode(@jwt_payload, ShopifyAPI::Context.api_secret_key, "HS256")
@auth_header = "Bearer #{@jwt_token}"
@expected_online_session_id = "#{@shop}_#{@user_id}"
@expected_offline_session_id = "offline_#{@shop}"
end

def test_gets_online_session_id_from_shopify_id_token
expected_session_id = "#{@shop}_#{@user_id}"
assert_equal(
expected_session_id,
@expected_online_session_id,
ShopifyAPI::Utils::SessionUtils.session_id_from_shopify_id_token(id_token: @jwt_token, online: true),
)
end

def test_gets_offline_session_id_from_shopify_id_token
expected_session_id = "offline_#{@shop}"
assert_equal(
expected_session_id,
@expected_offline_session_id,
ShopifyAPI::Utils::SessionUtils.session_id_from_shopify_id_token(id_token: @jwt_token, online: false),
)
end
Expand All @@ -50,11 +50,16 @@ def test_session_id_from_shopify_id_token_raises_invalid_jwt_errors
end

def test_session_id_from_shopify_id_token_raises_missing_jwt_token_error
error = assert_raises(ShopifyAPI::Errors::MissingJwtTokenError) do
ShopifyAPI::Utils::SessionUtils.session_id_from_shopify_id_token(id_token: nil, online: true)
end
[
nil,
"",
].each do |missing_jwt|
error = assert_raises(ShopifyAPI::Errors::MissingJwtTokenError) do
ShopifyAPI::Utils::SessionUtils.session_id_from_shopify_id_token(id_token: missing_jwt, online: true)
end

assert_equal("Missing Shopify ID Token", error.message)
assert_equal("Missing Shopify ID Token", error.message)
end
end

def test_non_embedded_app_current_session_id_raises_cookie_not_found_error
Expand Down Expand Up @@ -105,36 +110,51 @@ def test_embedded_app_current_session_id_raises_missing_jwt_token_error
ShopifyAPI::Utils::SessionUtils.current_session_id("", nil, true)
end

assert_equal("Missing Bearer token in authorization header", error.message)
assert_equal("Missing Shopify ID Token", error.message)
end

def test_embedded_app_current_session_id_returns_online_id_from_auth_header
ShopifyAPI::Context.stubs(:embedded?).returns(true)
expected_session_id = "#{@shop}_#{@user_id}"

assert_equal(
expected_session_id,
@expected_online_session_id,
ShopifyAPI::Utils::SessionUtils.current_session_id(@auth_header, nil, true),
)
end

def test_embedded_app_current_session_id_returns_offline_id_from_auth_header
ShopifyAPI::Context.stubs(:embedded?).returns(true)
expected_session_id = "offline_#{@shop}"

assert_equal(
expected_session_id,
@expected_offline_session_id,
ShopifyAPI::Utils::SessionUtils.current_session_id(@auth_header, nil, false),
)
end

def test_embedded_app_current_session_id_returns_online_id_from_shopify_id_token
ShopifyAPI::Context.stubs(:embedded?).returns(true)

assert_equal(
@expected_online_session_id,
ShopifyAPI::Utils::SessionUtils.current_session_id(@jwt_token, nil, true),
)
end

def test_embedded_app_current_session_id_returns_offline_id_from_shopify_id_token
ShopifyAPI::Context.stubs(:embedded?).returns(true)

assert_equal(
@expected_offline_session_id,
ShopifyAPI::Utils::SessionUtils.current_session_id(@jwt_token, nil, false),
)
end

def test_embedded_app_current_session_id_returns_id_from_auth_header_even_with_cookies
ShopifyAPI::Context.stubs(:embedded?).returns(true)
cookies = { ShopifyAPI::Auth::Oauth::SessionCookie::SESSION_COOKIE_NAME => "cookie_value" }
expected_session_id = "#{@shop}_#{@user_id}"

assert_equal(
expected_session_id,
@expected_online_session_id,
ShopifyAPI::Utils::SessionUtils.current_session_id(@auth_header, cookies, true),
)
end
Expand Down

0 comments on commit 27de2f3

Please sign in to comment.