stytch 9.0.0 → 9.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c5075518300c9fb8d82d98b80851825a1bfc72d61b637dbbbc54df07ad4b40f9
4
- data.tar.gz: e4abd2aec41c59f9d9605f0c6f43a62d5d4126991cfe89b5e96ad293a33922d5
3
+ metadata.gz: 833c91cba84e4cbbe5fd094bdf3d7ede5c0b351df7ebfab729fbaacdc181b14a
4
+ data.tar.gz: eccd3e064c0e2ba7bf0a7cbcc9f60b2aadaf25c0db70bee8c0c13646d30a6842
5
5
  SHA512:
6
- metadata.gz: 29a88d3485f4cabefe89721a83506e0dcbe64d8864780eec0508da70f5d308a204fa427cd0fb8e0c725c07bb45c20f37d182cb3f75e2694536f562b863a35ce9
7
- data.tar.gz: 6eaf332fea8ba9eb38da3af8d6eea7376b947a97e93f6478c0e149cc44d35236d9f148ee42e7179fb83ec6fa743076c806a7fc5b6c9e19e584763a3d2a5a2297
6
+ metadata.gz: c73c79869bb8e2bd29dac4307aa3dc4ba7b7a1c76eb1d5a780b29e2b62f2abcd2fe64244d654e37c99c160b8b5f1f6f762e02c59ea0510da034ebfb550c8d6ca
7
+ data.tar.gz: 07e99d0cd758a18aa37a20fe830ce7ba6ecfb19e9d6ec63a85870a12183b2da1ead1ec65315bee283d9f1b034f9f73be8b04aff9e5ff7fcd387867217cc92145
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  require:
2
- - rubocop-rspec
2
+ - rubocop-rspec
3
3
 
4
4
  AllCops:
5
5
  NewCops: disable
data/lib/stytch/errors.rb CHANGED
@@ -49,4 +49,11 @@ module Stytch
49
49
  super(msg)
50
50
  end
51
51
  end
52
+
53
+ class M2MPermissionError < StandardError
54
+ def initialize(has_scopes, required_scopes)
55
+ msg = "Missing at least one required scope from #{required_scopes} for M2M request with scopes #{has_scopes}"
56
+ super(msg)
57
+ end
58
+ end
52
59
  end
data/lib/stytch/m2m.rb CHANGED
@@ -96,6 +96,10 @@ module Stytch
96
96
  # max_token_age::
97
97
  # The maximum possible lifetime in seconds for the token to be valid.
98
98
  # The type of this field is nilable +Integer+.
99
+ # scope_authorization_func::
100
+ # A function to check if the token has the required scopes. This defaults to a function that assumes
101
+ # scopes are either direct string matches or written in the form "action:resource". See the
102
+ # documentation for +perform_authorization_check+ for more information.
99
103
  # == Returns:
100
104
  # +nil+ if the token could not be validated, or an object with the following fields:
101
105
  # scopes::
@@ -107,7 +111,12 @@ module Stytch
107
111
  # custom_claims::
108
112
  # A map of custom claims present in the token.
109
113
  # The type of this field is +object+.
110
- def authenticate_token(access_token:, required_scopes: nil, max_token_age: nil)
114
+ def authenticate_token(
115
+ access_token:,
116
+ required_scopes: nil,
117
+ max_token_age: nil,
118
+ scope_authorization_func: method(:perform_authorization_check)
119
+ )
111
120
  # Intentionally allow this to re-raise if authentication fails
112
121
  decoded_jwt = authenticate_token_local(access_token)
113
122
 
@@ -119,14 +128,50 @@ module Stytch
119
128
  resp = marshal_jwt_into_response(decoded_jwt)
120
129
 
121
130
  unless required_scopes.nil?
122
- for scope in required_scopes
123
- raise TokenMissingScopeError, scope unless resp['scopes'].include?(scope)
124
- end
131
+ is_authorized = scope_authorization_func.call(
132
+ has_scopes: resp['scopes'],
133
+ required_scopes: required_scopes
134
+ )
135
+ raise M2MPermissionError.new(resp['scopes'], required_scopes) unless is_authorized
125
136
  end
126
137
 
127
138
  resp
128
139
  end
129
140
 
141
+ # Performs an authorization check against an M2M client and a set of required
142
+ # scopes. Returns true if the client has all the required scopes, false otherwise.
143
+ # A scope can match if the client has a wildcard resource or the specific resource.
144
+ # This function assumes that scopes are of the form "action:resource" or just
145
+ # "specific_scope". It is _also_ possible to represent scopes as "resource:action",
146
+ # but it is ultimately up to the developer to ensure consistency in the scopes format.
147
+ # Note that a scope of "*" will only match another literal "*" because wildcards are
148
+ # *not* supported in the prefix piece of a scope.
149
+ def perform_authorization_check(
150
+ has_scopes:,
151
+ required_scopes:
152
+ )
153
+ client_scopes = Hash.new { |hash, key| hash[key] = Set.new }
154
+ has_scopes.each do |scope|
155
+ action = scope
156
+ resource = '-'
157
+ action, resource = scope.split(':') if scope.include?(':')
158
+ client_scopes[action].add(resource)
159
+ end
160
+
161
+ required_scopes.each do |required_scope|
162
+ required_action = required_scope
163
+ required_resource = '-'
164
+ required_action, required_resource = required_scope.split(':') if required_scope.include?(':')
165
+ return false unless client_scopes.key?(required_action)
166
+
167
+ resources = client_scopes[required_action]
168
+ # The client can either have a wildcard resource or the specific resource
169
+ return false unless resources.include?('*') || resources.include?(required_resource)
170
+ end
171
+
172
+ true
173
+ end
174
+
130
175
  # Parse a M2M token and verify the signature locally (without calling /authenticate in the API)
131
176
  def authenticate_token_local(jwt)
132
177
  issuer = 'stytch.com/' + @project_id
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Stytch
4
- VERSION = '9.0.0'
4
+ VERSION = '9.1.0'
5
5
  end
data/stytch.gemspec CHANGED
@@ -30,6 +30,6 @@ Gem::Specification.new do |spec|
30
30
  spec.add_dependency 'jwt', '>= 2.3.0'
31
31
 
32
32
  spec.add_development_dependency 'rspec', '~> 3.11.0'
33
- spec.add_development_dependency 'rubocop', '1.56.3'
33
+ spec.add_development_dependency 'rubocop', '1.64.1'
34
34
  spec.add_development_dependency 'rubocop-rspec', '2.24.0'
35
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stytch
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.0.0
4
+ version: 9.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - stytch
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-03 00:00:00.000000000 Z
11
+ date: 2024-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -78,14 +78,14 @@ dependencies:
78
78
  requirements:
79
79
  - - '='
80
80
  - !ruby/object:Gem::Version
81
- version: 1.56.3
81
+ version: 1.64.1
82
82
  type: :development
83
83
  prerelease: false
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - '='
87
87
  - !ruby/object:Gem::Version
88
- version: 1.56.3
88
+ version: 1.64.1
89
89
  - !ruby/object:Gem::Dependency
90
90
  name: rubocop-rspec
91
91
  requirement: !ruby/object:Gem::Requirement