shopify_api 14.2.0 → 14.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/Gemfile.lock +1 -1
- data/docs/getting_started.md +17 -2
- data/lib/shopify_api/auth/jwt_payload.rb +11 -3
- data/lib/shopify_api/utils/session_utils.rb +24 -17
- data/lib/shopify_api/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f2fd17eb9b42d6054e8b676c5d446cbc9890b7156f5c4b402a5efb776ad1421
|
4
|
+
data.tar.gz: 1deefc0fdcc79f57b70fb1fbeb2072916847b8d68c614b4b150dafd86f0ff6d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3cfdd1a407afb83e8557d607c65dd74322a7ca944fe58b2b42d68a911917442f51c78a0a7e59759a4fca59ae063c7af253ad8a297614a409621c52e0baf60ee6
|
7
|
+
data.tar.gz: e218a6a5c77d9de8e3b0a755c0bcb1b4941bb5cfba503564ffa4ca0a59c19b76e8c0cb56cb1ee458091bd43004fa3b16c200fa4696b058a0b90c9c3475bd37d0
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,16 @@ Note: For changes to the API, see https://shopify.dev/changelog?filter=api
|
|
4
4
|
|
5
5
|
## Unreleased
|
6
6
|
|
7
|
+
## 14.3.0
|
8
|
+
- [#1312](https://github.com/Shopify/shopify-api-ruby/pull/1312) Use same leeway for `exp` and `nbf` when parsing JWT
|
9
|
+
- [#1314](https://github.com/Shopify/shopify-api-ruby/pull/1314)
|
10
|
+
- Add new session util method `SessionUtils::session_id_from_shopify_id_token`
|
11
|
+
- `SessionUtils::current_session_id` now accepts shopify Id token in the format of `Bearer this_token` or just `this_token`
|
12
|
+
- [#1315](https://github.com/Shopify/shopify-api-ruby/pull/1315) Add helper/alias methods to `ShopifyAPI::Auth::JwtPayload`:
|
13
|
+
- `shopify_domain` alias for `shop` - returns the sanitized shop domain
|
14
|
+
- `shopify_user_id` - returns the user Id (`sub`) as an Integer value
|
15
|
+
- `expires_at` alias for `exp` - returns the expiration time
|
16
|
+
|
7
17
|
## 14.2.0
|
8
18
|
- [#1309](https://github.com/Shopify/shopify-api-ruby/pull/1309) Add `Session#copy_attributes_from` method
|
9
19
|
|
data/Gemfile.lock
CHANGED
data/docs/getting_started.md
CHANGED
@@ -46,13 +46,28 @@ Session persistence is handled by the [ShopifyApp](https://github.com/Shopify/sh
|
|
46
46
|
#### Cookie
|
47
47
|
Cookie based authentication is not supported for embedded apps due to browsers dropping support for third party cookies due to security concerns. Non-embedded apps are able to use cookies for session storage/retrieval.
|
48
48
|
|
49
|
-
For *non-embedded* apps, you can pass the cookies into
|
49
|
+
For *non-embedded* apps, you can pass the cookies into:
|
50
|
+
- `ShopifyAPI::Utils::SessionUtils.current_session_id(nil, cookies, true)` for online (user) sessions or
|
51
|
+
- `ShopifyAPI::Utils::SessionUtils.current_session_id(nil, cookies, false)` for offline (store) sessions.
|
50
52
|
|
51
53
|
#### Getting Session ID From Embedded Requests
|
52
|
-
For *embedded* apps, 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. This function needs an `auth_header` which is the `HTTP_AUTHORIZATION` header.
|
53
54
|
|
54
55
|
If your app uses client side rendering instead of server side rendering, you will need to use App Bridge's [authenticatedFetch](https://shopify.dev/docs/apps/auth/oauth/session-tokens/getting-started) to make authenticated API requests from the client.
|
55
56
|
|
57
|
+
For *embedded* apps:
|
58
|
+
|
59
|
+
If you have an `HTTP_AUTHORIZATION` header or `id_token` from the request URL params , you can pass that as `shopify_id_token` into:
|
60
|
+
- `ShopifyAPI::Utils::SessionUtils.current_session_id(shopify_id_token, nil, true)` for online (user) sessions or
|
61
|
+
- `ShopifyAPI::Utils::SessionUtils.current_session_id(shopify_id_token, nil, false)` for offline (store) sessions.
|
62
|
+
|
63
|
+
`current_session_id` accepts shopify_id_token in the format of `Bearer this_token` or just `this_token`.
|
64
|
+
|
65
|
+
You can also use this method to get session ID:
|
66
|
+
- `ShopifyAPI::Utils::SessionUtils::session_id_from_shopify_id_token(id_token: id_token, online: true)` for online (user) sessions or
|
67
|
+
- `ShopifyAPI::Utils::SessionUtils::session_id_from_shopify_id_token(id_token: id_token, online: false)` for offline (store) sessions.
|
68
|
+
|
69
|
+
`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`.
|
70
|
+
|
56
71
|
#### Start Making Authenticated Shopify Requests
|
57
72
|
|
58
73
|
You can now start making authenticated Shopify API calls using the Admin [REST](usage/rest.md) or [GraphQL](usage/graphql.md) Clients or the [Storefront GraphQL Client](usage/graphql_storefront.md).
|
@@ -6,7 +6,8 @@ module ShopifyAPI
|
|
6
6
|
class JwtPayload
|
7
7
|
extend T::Sig
|
8
8
|
|
9
|
-
|
9
|
+
JWT_LEEWAY = 10
|
10
|
+
JWT_EXPIRATION_LEEWAY = JWT_LEEWAY
|
10
11
|
|
11
12
|
sig { returns(String) }
|
12
13
|
attr_reader :iss, :dest, :aud, :sub, :jti, :sid
|
@@ -14,6 +15,8 @@ module ShopifyAPI
|
|
14
15
|
sig { returns(Integer) }
|
15
16
|
attr_reader :exp, :nbf, :iat
|
16
17
|
|
18
|
+
alias_method :expire_at, :exp
|
19
|
+
|
17
20
|
sig { params(token: String).void }
|
18
21
|
def initialize(token)
|
19
22
|
payload_hash = begin
|
@@ -42,6 +45,12 @@ module ShopifyAPI
|
|
42
45
|
def shop
|
43
46
|
@dest.gsub("https://", "")
|
44
47
|
end
|
48
|
+
alias_method :shopify_domain, :shop
|
49
|
+
|
50
|
+
sig { returns(Integer) }
|
51
|
+
def shopify_user_id
|
52
|
+
@sub.to_i
|
53
|
+
end
|
45
54
|
|
46
55
|
# TODO: Remove before releasing v11
|
47
56
|
sig { params(shop: String).returns(T::Boolean) }
|
@@ -73,8 +82,7 @@ module ShopifyAPI
|
|
73
82
|
|
74
83
|
sig { params(token: String, api_secret_key: String).returns(T::Hash[String, T.untyped]) }
|
75
84
|
def decode_token(token, api_secret_key)
|
76
|
-
JWT.decode(token, api_secret_key, true,
|
77
|
-
{ exp_leeway: JWT_EXPIRATION_LEEWAY, algorithm: "HS256" })[0]
|
85
|
+
JWT.decode(token, api_secret_key, true, leeway: JWT_LEEWAY, algorithm: "HS256")[0]
|
78
86
|
rescue JWT::DecodeError => err
|
79
87
|
raise ShopifyAPI::Errors::InvalidJwtTokenError, "Error decoding session token: #{err.message}"
|
80
88
|
end
|
@@ -11,28 +11,16 @@ module ShopifyAPI
|
|
11
11
|
|
12
12
|
sig do
|
13
13
|
params(
|
14
|
-
|
14
|
+
shopify_id_token: T.nilable(String),
|
15
15
|
cookies: T.nilable(T::Hash[String, String]),
|
16
16
|
online: T::Boolean,
|
17
17
|
).returns(T.nilable(String))
|
18
18
|
end
|
19
|
-
def current_session_id(
|
19
|
+
def current_session_id(shopify_id_token, cookies, online)
|
20
20
|
if Context.embedded?
|
21
|
-
if
|
22
|
-
|
23
|
-
|
24
|
-
ShopifyAPI::Logger.warn("Missing Bearer token in authorization header")
|
25
|
-
raise Errors::MissingJwtTokenError, "Missing Bearer token in authorization header"
|
26
|
-
end
|
27
|
-
|
28
|
-
jwt_payload = Auth::JwtPayload.new(T.must(matches[1]))
|
29
|
-
shop = jwt_payload.shop
|
30
|
-
|
31
|
-
if online
|
32
|
-
jwt_session_id(shop, jwt_payload.sub)
|
33
|
-
else
|
34
|
-
offline_session_id(shop)
|
35
|
-
end
|
21
|
+
if shopify_id_token
|
22
|
+
id_token = shopify_id_token.gsub("Bearer ", "")
|
23
|
+
session_id_from_shopify_id_token(id_token: id_token, online: online)
|
36
24
|
else
|
37
25
|
# falling back to session cookie
|
38
26
|
raise Errors::CookieNotFoundError, "JWT token or Session cookie not found for app" unless
|
@@ -48,6 +36,25 @@ module ShopifyAPI
|
|
48
36
|
end
|
49
37
|
end
|
50
38
|
|
39
|
+
sig do
|
40
|
+
params(
|
41
|
+
id_token: T.nilable(String),
|
42
|
+
online: T::Boolean,
|
43
|
+
).returns(String)
|
44
|
+
end
|
45
|
+
def session_id_from_shopify_id_token(id_token:, online:)
|
46
|
+
raise Errors::MissingJwtTokenError, "Missing Shopify ID Token" if id_token.nil? || id_token.empty?
|
47
|
+
|
48
|
+
payload = Auth::JwtPayload.new(id_token)
|
49
|
+
shop = payload.shop
|
50
|
+
|
51
|
+
if online
|
52
|
+
jwt_session_id(shop, payload.sub)
|
53
|
+
else
|
54
|
+
offline_session_id(shop)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
51
58
|
sig { params(shop: String, user_id: String).returns(String) }
|
52
59
|
def jwt_session_id(shop, user_id)
|
53
60
|
"#{shop}_#{user_id}"
|
data/lib/shopify_api/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shopify_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 14.
|
4
|
+
version: 14.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-04-
|
11
|
+
date: 2024-04-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|