stytch 6.4.0 → 9.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +13 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +22 -0
- data/DEVELOPMENT.md +5 -2
- data/README.md +52 -3
- data/lib/stytch/b2b_client.rb +18 -3
- data/lib/stytch/b2b_discovery.rb +73 -33
- data/lib/stytch/b2b_magic_links.rb +63 -24
- data/lib/stytch/b2b_oauth.rb +31 -16
- data/lib/stytch/b2b_organizations.rb +788 -51
- data/lib/stytch/b2b_otp.rb +35 -10
- data/lib/stytch/b2b_passwords.rb +141 -44
- data/lib/stytch/b2b_rbac.rb +47 -0
- data/lib/stytch/b2b_recovery_codes.rb +196 -0
- data/lib/stytch/b2b_scim.rb +496 -0
- data/lib/stytch/b2b_sessions.rb +299 -15
- data/lib/stytch/b2b_sso.rb +486 -24
- data/lib/stytch/b2b_totps.rb +255 -0
- data/lib/stytch/client.rb +6 -3
- data/lib/stytch/crypto_wallets.rb +19 -4
- data/lib/stytch/errors.rb +21 -0
- data/lib/stytch/m2m.rb +80 -19
- data/lib/stytch/magic_links.rb +20 -12
- data/lib/stytch/method_options.rb +22 -0
- data/lib/stytch/oauth.rb +10 -4
- data/lib/stytch/otps.rb +27 -17
- data/lib/stytch/passwords.rb +67 -19
- data/lib/stytch/project.rb +26 -0
- data/lib/stytch/rbac_local.rb +58 -0
- data/lib/stytch/request_helper.rb +12 -8
- data/lib/stytch/sessions.rb +131 -31
- data/lib/stytch/totps.rb +9 -5
- data/lib/stytch/users.rb +30 -16
- data/lib/stytch/version.rb +1 -1
- data/lib/stytch/webauthn.rb +126 -24
- data/lib/stytch.rb +1 -0
- data/stytch.gemspec +2 -0
- metadata +42 -6
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# !!!
|
4
|
+
# WARNING: This file is autogenerated
|
5
|
+
# Only modify code within MANUAL() sections
|
6
|
+
# or your changes may be overwritten later!
|
7
|
+
# !!!
|
8
|
+
|
9
|
+
require_relative 'request_helper'
|
10
|
+
|
11
|
+
module Stytch
|
12
|
+
class Project
|
13
|
+
include Stytch::RequestHelper
|
14
|
+
|
15
|
+
def initialize(connection)
|
16
|
+
@connection = connection
|
17
|
+
end
|
18
|
+
|
19
|
+
def metrics
|
20
|
+
headers = {}
|
21
|
+
query_params = {}
|
22
|
+
request = request_with_query_params('/v1/projects/metrics', query_params)
|
23
|
+
get_request(request, headers)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'errors'
|
4
|
+
require_relative 'request_helper'
|
5
|
+
|
6
|
+
module StytchB2B
|
7
|
+
class PolicyCache
|
8
|
+
def initialize(rbac_client:)
|
9
|
+
@rbac_client = rbac_client
|
10
|
+
@policy_last_update = 0
|
11
|
+
@cached_policy = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def reload_policy
|
15
|
+
@cached_policy = @rbac_client.policy['policy']
|
16
|
+
@policy_last_update = Time.now.to_i
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_policy(invalidate: false)
|
20
|
+
reload_policy if invalidate || @cached_policy.nil? || @policy_last_update < Time.now.to_i - 300
|
21
|
+
@cached_policy
|
22
|
+
end
|
23
|
+
|
24
|
+
# Performs an authorization check against the project's policy and a set of roles. If the
|
25
|
+
# check succeeds, this method will return. If the check fails, a PermissionError
|
26
|
+
# will be raised. It's also possible for a TenancyError to be raised if the
|
27
|
+
# subject_org_id does not match the authZ request organization_id.
|
28
|
+
# authorization_check is an object with keys 'action', 'resource_id', and 'organization_id'
|
29
|
+
def perform_authorization_check(
|
30
|
+
subject_roles:,
|
31
|
+
subject_org_id:,
|
32
|
+
authorization_check:
|
33
|
+
)
|
34
|
+
request_org_id = authorization_check['organization_id']
|
35
|
+
raise Stytch::TenancyError.new(subject_org_id, request_org_id) if request_org_id != subject_org_id
|
36
|
+
|
37
|
+
policy = get_policy
|
38
|
+
|
39
|
+
for role in policy['roles']
|
40
|
+
next unless subject_roles.include?(role['role_id'])
|
41
|
+
|
42
|
+
for permission in role['permissions']
|
43
|
+
actions = permission['actions']
|
44
|
+
resource = permission['resource_id']
|
45
|
+
has_matching_action = actions.include?('*') || actions.include?(authorization_check['action'])
|
46
|
+
has_matching_resource = resource == authorization_check['resource_id']
|
47
|
+
if has_matching_action && has_matching_resource
|
48
|
+
# All good
|
49
|
+
return
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# If we get here, we didn't find a matching permission
|
55
|
+
raise Stytch::PermissionError, authorization_check
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -2,29 +2,33 @@
|
|
2
2
|
|
3
3
|
module Stytch
|
4
4
|
module RequestHelper
|
5
|
-
def get_request(path)
|
5
|
+
def get_request(path, headers)
|
6
6
|
@connection.get(
|
7
|
-
path
|
7
|
+
path,
|
8
|
+
headers
|
8
9
|
).body
|
9
10
|
end
|
10
11
|
|
11
|
-
def post_request(path, payload)
|
12
|
+
def post_request(path, payload, headers)
|
12
13
|
@connection.post(
|
13
14
|
path,
|
14
|
-
payload
|
15
|
+
payload,
|
16
|
+
headers
|
15
17
|
).body
|
16
18
|
end
|
17
19
|
|
18
|
-
def put_request(path, payload)
|
20
|
+
def put_request(path, payload, headers)
|
19
21
|
@connection.put(
|
20
22
|
path,
|
21
|
-
payload
|
23
|
+
payload,
|
24
|
+
headers
|
22
25
|
).body
|
23
26
|
end
|
24
27
|
|
25
|
-
def delete_request(path)
|
28
|
+
def delete_request(path, headers)
|
26
29
|
@connection.delete(
|
27
|
-
path
|
30
|
+
path,
|
31
|
+
headers
|
28
32
|
).body
|
29
33
|
end
|
30
34
|
|
data/lib/stytch/sessions.rb
CHANGED
@@ -54,14 +54,17 @@ module Stytch
|
|
54
54
|
def get(
|
55
55
|
user_id:
|
56
56
|
)
|
57
|
+
headers = {}
|
57
58
|
query_params = {
|
58
59
|
user_id: user_id
|
59
60
|
}
|
60
61
|
request = request_with_query_params('/v1/sessions', query_params)
|
61
|
-
get_request(request)
|
62
|
+
get_request(request, headers)
|
62
63
|
end
|
63
64
|
|
64
|
-
# Authenticate a session token and retrieve associated session data. If `session_duration_minutes` is included, update the lifetime of the session to be that many minutes from now. All timestamps are formatted according to the RFC 3339 standard and are expressed in UTC, e.g. `2021-12-29T12:33:09Z`. This endpoint requires exactly one `session_jwt` or `session_token` as part of the request. If both are included you will receive a `too_many_session_arguments` error.
|
65
|
+
# Authenticate a session token or session JWT and retrieve associated session data. If `session_duration_minutes` is included, update the lifetime of the session to be that many minutes from now. All timestamps are formatted according to the RFC 3339 standard and are expressed in UTC, e.g. `2021-12-29T12:33:09Z`. This endpoint requires exactly one `session_jwt` or `session_token` as part of the request. If both are included, you will receive a `too_many_session_arguments` error.
|
66
|
+
#
|
67
|
+
# You may provide a JWT that needs to be refreshed and is expired according to its `exp` claim. A new JWT will be returned if both the signature and the underlying Session are still valid. See our [How to use Stytch Session JWTs](https://stytch.com/docs/guides/sessions/using-jwts) guide for more information.
|
65
68
|
#
|
66
69
|
# == Parameters:
|
67
70
|
# session_token::
|
@@ -108,13 +111,14 @@ module Stytch
|
|
108
111
|
session_jwt: nil,
|
109
112
|
session_custom_claims: nil
|
110
113
|
)
|
114
|
+
headers = {}
|
111
115
|
request = {}
|
112
116
|
request[:session_token] = session_token unless session_token.nil?
|
113
117
|
request[:session_duration_minutes] = session_duration_minutes unless session_duration_minutes.nil?
|
114
118
|
request[:session_jwt] = session_jwt unless session_jwt.nil?
|
115
119
|
request[:session_custom_claims] = session_custom_claims unless session_custom_claims.nil?
|
116
120
|
|
117
|
-
post_request('/v1/sessions/authenticate', request)
|
121
|
+
post_request('/v1/sessions/authenticate', request, headers)
|
118
122
|
end
|
119
123
|
|
120
124
|
# Revoke a Session, immediately invalidating all of its session tokens. You can revoke a session in three ways: using its ID, or using one of its session tokens, or one of its JWTs. This endpoint requires exactly one of those to be included in the request. It will return an error if multiple are present.
|
@@ -143,15 +147,90 @@ module Stytch
|
|
143
147
|
session_token: nil,
|
144
148
|
session_jwt: nil
|
145
149
|
)
|
150
|
+
headers = {}
|
146
151
|
request = {}
|
147
152
|
request[:session_id] = session_id unless session_id.nil?
|
148
153
|
request[:session_token] = session_token unless session_token.nil?
|
149
154
|
request[:session_jwt] = session_jwt unless session_jwt.nil?
|
150
155
|
|
151
|
-
post_request('/v1/sessions/revoke', request)
|
156
|
+
post_request('/v1/sessions/revoke', request, headers)
|
152
157
|
end
|
153
158
|
|
154
|
-
#
|
159
|
+
# Migrate a session from an external OIDC compliant endpoint. Stytch will call the external UserInfo endpoint defined in your Stytch Project settings in the [Dashboard](/dashboard), and then perform a lookup using the `session_token`. If the response contains a valid email address, Stytch will attempt to match that email address with an existing User and create a Stytch Session. You will need to create the user before using this endpoint.
|
160
|
+
#
|
161
|
+
# == Parameters:
|
162
|
+
# session_token::
|
163
|
+
# The authorization token Stytch will pass in to the external userinfo endpoint.
|
164
|
+
# The type of this field is +String+.
|
165
|
+
# session_duration_minutes::
|
166
|
+
# Set the session lifetime to be this many minutes from now. This will start a new session if one doesn't already exist,
|
167
|
+
# returning both an opaque `session_token` and `session_jwt` for this session. Remember that the `session_jwt` will have a fixed lifetime of
|
168
|
+
# five minutes regardless of the underlying session duration, and will need to be refreshed over time.
|
169
|
+
#
|
170
|
+
# This value must be a minimum of 5 and a maximum of 527040 minutes (366 days).
|
171
|
+
#
|
172
|
+
# If a `session_token` or `session_jwt` is provided then a successful authentication will continue to extend the session this many minutes.
|
173
|
+
#
|
174
|
+
# If the `session_duration_minutes` parameter is not specified, a Stytch session will not be created.
|
175
|
+
# The type of this field is nilable +Integer+.
|
176
|
+
# session_custom_claims::
|
177
|
+
# Add a custom claims map to the Session being authenticated. Claims are only created if a Session is initialized by providing a value in `session_duration_minutes`. Claims will be included on the Session object and in the JWT. To update a key in an existing Session, supply a new value. To delete a key, supply a null value.
|
178
|
+
#
|
179
|
+
# Custom claims made with reserved claims ("iss", "sub", "aud", "exp", "nbf", "iat", "jti") will be ignored. Total custom claims size cannot exceed four kilobytes.
|
180
|
+
# The type of this field is nilable +object+.
|
181
|
+
#
|
182
|
+
# == Returns:
|
183
|
+
# An object with the following fields:
|
184
|
+
# request_id::
|
185
|
+
# Globally unique UUID that is returned with every API call. This value is important to log for debugging purposes; we may ask for this value to help identify a specific API call when helping you debug an issue.
|
186
|
+
# The type of this field is +String+.
|
187
|
+
# user_id::
|
188
|
+
# The unique ID of the affected User.
|
189
|
+
# The type of this field is +String+.
|
190
|
+
# session_token::
|
191
|
+
# A secret token for a given Stytch Session.
|
192
|
+
# The type of this field is +String+.
|
193
|
+
# session_jwt::
|
194
|
+
# The JSON Web Token (JWT) for a given Stytch Session.
|
195
|
+
# The type of this field is +String+.
|
196
|
+
# user::
|
197
|
+
# The `user` object affected by this API call. See the [Get user endpoint](https://stytch.com/docs/api/get-user) for complete response field details.
|
198
|
+
# The type of this field is +User+ (+object+).
|
199
|
+
# status_code::
|
200
|
+
# (no documentation yet)
|
201
|
+
# The type of this field is +Integer+.
|
202
|
+
# session::
|
203
|
+
# If you initiate a Session, by including `session_duration_minutes` in your authenticate call, you'll receive a full Session object in the response.
|
204
|
+
#
|
205
|
+
# See [GET sessions](https://stytch.com/docs/api/session-get) for complete response fields.
|
206
|
+
#
|
207
|
+
# The type of this field is nilable +Session+ (+object+).
|
208
|
+
def migrate(
|
209
|
+
session_token:,
|
210
|
+
session_duration_minutes: nil,
|
211
|
+
session_custom_claims: nil
|
212
|
+
)
|
213
|
+
headers = {}
|
214
|
+
request = {
|
215
|
+
session_token: session_token
|
216
|
+
}
|
217
|
+
request[:session_duration_minutes] = session_duration_minutes unless session_duration_minutes.nil?
|
218
|
+
request[:session_custom_claims] = session_custom_claims unless session_custom_claims.nil?
|
219
|
+
|
220
|
+
post_request('/v1/sessions/migrate', request, headers)
|
221
|
+
end
|
222
|
+
|
223
|
+
# Get the JSON Web Key Set (JWKS) for a project.
|
224
|
+
#
|
225
|
+
# JWKS are rotated every ~6 months. Upon rotation, new JWTs will be signed using the new key set, and both key sets will be returned by this endpoint for a period of 1 month.
|
226
|
+
#
|
227
|
+
# JWTs have a set lifetime of 5 minutes, so there will be a 5 minute period where some JWTs will be signed by the old JWKS, and some JWTs will be signed by the new JWKS. The correct JWKS to use for validation is determined by matching the `kid` value of the JWT and JWKS.
|
228
|
+
#
|
229
|
+
# If you're using one of our [backend SDKs](https://stytch.com/docs/sdks), the JWKS roll will be handled for you.
|
230
|
+
#
|
231
|
+
# If you're using your own JWT validation library, many have built-in support for JWKS rotation, and you'll just need to supply this API endpoint. If not, your application should decide which JWKS to use for validation by inspecting the `kid` value.
|
232
|
+
#
|
233
|
+
# See our [How to use Stytch Session JWTs](https://stytch.com/docs/guides/sessions/using-jwts) guide for more information.
|
155
234
|
#
|
156
235
|
# == Parameters:
|
157
236
|
# project_id::
|
@@ -172,9 +251,10 @@ module Stytch
|
|
172
251
|
def get_jwks(
|
173
252
|
project_id:
|
174
253
|
)
|
254
|
+
headers = {}
|
175
255
|
query_params = {}
|
176
256
|
request = request_with_query_params("/v1/sessions/jwks/#{project_id}", query_params)
|
177
|
-
get_request(request)
|
257
|
+
get_request(request, headers)
|
178
258
|
end
|
179
259
|
|
180
260
|
# MANUAL(Sessions::authenticate_jwt)(SERVICE_METHOD)
|
@@ -186,12 +266,18 @@ module Stytch
|
|
186
266
|
# If max_token_age_seconds is set and the JWT was issued (based on the "iat" claim) less than
|
187
267
|
# max_token_age_seconds seconds ago, then just verify locally and don't call the API
|
188
268
|
# To force remote validation for all tokens, set max_token_age_seconds to 0 or call authenticate()
|
269
|
+
# If max_token_age_seconds is not supplied 300 seconds will be used as the default.
|
270
|
+
# If clock_tolerance_seconds is not supplied 0 seconds will be used as the default.
|
189
271
|
def authenticate_jwt(
|
190
272
|
session_jwt,
|
191
273
|
max_token_age_seconds: nil,
|
192
274
|
session_duration_minutes: nil,
|
193
|
-
session_custom_claims: nil
|
275
|
+
session_custom_claims: nil,
|
276
|
+
clock_tolerance_seconds: nil
|
194
277
|
)
|
278
|
+
max_token_age_seconds = 300 if max_token_age_seconds.nil?
|
279
|
+
clock_tolerance_seconds = 0 if clock_tolerance_seconds.nil?
|
280
|
+
|
195
281
|
if max_token_age_seconds == 0
|
196
282
|
return authenticate(
|
197
283
|
session_jwt: session_jwt,
|
@@ -200,18 +286,18 @@ module Stytch
|
|
200
286
|
)
|
201
287
|
end
|
202
288
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
289
|
+
session = authenticate_jwt_local(
|
290
|
+
session_jwt,
|
291
|
+
max_token_age_seconds: max_token_age_seconds,
|
292
|
+
clock_tolerance_seconds: clock_tolerance_seconds
|
293
|
+
)
|
294
|
+
return session unless session.nil?
|
295
|
+
|
296
|
+
authenticate(
|
297
|
+
session_jwt: session_jwt,
|
298
|
+
session_duration_minutes: session_duration_minutes,
|
299
|
+
session_custom_claims: session_custom_claims
|
300
|
+
)
|
215
301
|
rescue StandardError
|
216
302
|
# JWT could not be verified locally. Check with the Stytch API.
|
217
303
|
authenticate(
|
@@ -225,12 +311,22 @@ module Stytch
|
|
225
311
|
# Uses the cached value to get the JWK but if it is unavailable, it calls the get_jwks()
|
226
312
|
# function to get the JWK
|
227
313
|
# This method never authenticates a JWT directly with the API
|
228
|
-
|
314
|
+
# If max_token_age_seconds is not supplied 300 seconds will be used as the default.
|
315
|
+
# If clock_tolerance_seconds is not supplied 0 seconds will be used as the default.
|
316
|
+
def authenticate_jwt_local(session_jwt, max_token_age_seconds: nil, clock_tolerance_seconds: nil)
|
317
|
+
max_token_age_seconds = 300 if max_token_age_seconds.nil?
|
318
|
+
clock_tolerance_seconds = 0 if clock_tolerance_seconds.nil?
|
319
|
+
|
229
320
|
issuer = 'stytch.com/' + @project_id
|
230
321
|
begin
|
231
322
|
decoded_token = JWT.decode session_jwt, nil, true,
|
232
|
-
{ jwks: @jwks_loader, iss: issuer, verify_iss: true, aud: @project_id, verify_aud: true, algorithms: ['RS256'] }
|
233
|
-
|
323
|
+
{ jwks: @jwks_loader, iss: issuer, verify_iss: true, aud: @project_id, verify_aud: true, algorithms: ['RS256'], nbf_leeway: clock_tolerance_seconds }
|
324
|
+
|
325
|
+
session = decoded_token[0]
|
326
|
+
iat_time = Time.at(session['iat']).to_datetime
|
327
|
+
return nil unless iat_time + max_token_age_seconds >= Time.now
|
328
|
+
|
329
|
+
session = marshal_jwt_into_session(session)
|
234
330
|
rescue JWT::InvalidIssuerError
|
235
331
|
raise JWTInvalidIssuerError
|
236
332
|
rescue JWT::InvalidAudError
|
@@ -240,6 +336,8 @@ module Stytch
|
|
240
336
|
rescue JWT::IncorrectAlgorithm
|
241
337
|
raise JWTIncorrectAlgorithmError
|
242
338
|
end
|
339
|
+
|
340
|
+
session
|
243
341
|
end
|
244
342
|
|
245
343
|
def marshal_jwt_into_session(jwt)
|
@@ -251,15 +349,17 @@ module Stytch
|
|
251
349
|
reserved_claims = ['aud', 'exp', 'iat', 'iss', 'jti', 'nbf', 'sub', stytch_claim]
|
252
350
|
custom_claims = jwt.reject { |key, _| reserved_claims.include?(key) }
|
253
351
|
{
|
254
|
-
'
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
352
|
+
'session' => {
|
353
|
+
'session_id' => jwt[stytch_claim]['id'],
|
354
|
+
'user_id' => jwt['sub'],
|
355
|
+
'started_at' => jwt[stytch_claim]['started_at'],
|
356
|
+
'last_accessed_at' => jwt[stytch_claim]['last_accessed_at'],
|
357
|
+
# For JWTs that include it, prefer the inner expires_at claim.
|
358
|
+
'expires_at' => expires_at,
|
359
|
+
'attributes' => jwt[stytch_claim]['attributes'],
|
360
|
+
'authentication_factors' => jwt[stytch_claim]['authentication_factors'],
|
361
|
+
'custom_claims' => custom_claims
|
362
|
+
}
|
263
363
|
}
|
264
364
|
end
|
265
365
|
# ENDMANUAL(Sessions::authenticate_jwt)
|
data/lib/stytch/totps.rb
CHANGED
@@ -23,7 +23,7 @@ module Stytch
|
|
23
23
|
# The `user_id` of an active user the TOTP registration should be tied to.
|
24
24
|
# The type of this field is +String+.
|
25
25
|
# expiration_minutes::
|
26
|
-
# The expiration for the TOTP instance. If the newly created TOTP is not authenticated within this time frame the TOTP will be unusable. Defaults to
|
26
|
+
# The expiration for the TOTP instance. If the newly created TOTP is not authenticated within this time frame the TOTP will be unusable. Defaults to 1440 (1 day) with a minimum of 5 and a maximum of 1440.
|
27
27
|
# The type of this field is nilable +Integer+.
|
28
28
|
#
|
29
29
|
# == Returns:
|
@@ -56,12 +56,13 @@ module Stytch
|
|
56
56
|
user_id:,
|
57
57
|
expiration_minutes: nil
|
58
58
|
)
|
59
|
+
headers = {}
|
59
60
|
request = {
|
60
61
|
user_id: user_id
|
61
62
|
}
|
62
63
|
request[:expiration_minutes] = expiration_minutes unless expiration_minutes.nil?
|
63
64
|
|
64
|
-
post_request('/v1/totps', request)
|
65
|
+
post_request('/v1/totps', request, headers)
|
65
66
|
end
|
66
67
|
|
67
68
|
# Authenticate a TOTP code entered by a user.
|
@@ -133,6 +134,7 @@ module Stytch
|
|
133
134
|
session_jwt: nil,
|
134
135
|
session_custom_claims: nil
|
135
136
|
)
|
137
|
+
headers = {}
|
136
138
|
request = {
|
137
139
|
user_id: user_id,
|
138
140
|
totp_code: totp_code
|
@@ -142,7 +144,7 @@ module Stytch
|
|
142
144
|
request[:session_jwt] = session_jwt unless session_jwt.nil?
|
143
145
|
request[:session_custom_claims] = session_custom_claims unless session_custom_claims.nil?
|
144
146
|
|
145
|
-
post_request('/v1/totps/authenticate', request)
|
147
|
+
post_request('/v1/totps/authenticate', request, headers)
|
146
148
|
end
|
147
149
|
|
148
150
|
# Retrieve the recovery codes for a TOTP instance tied to a User.
|
@@ -169,11 +171,12 @@ module Stytch
|
|
169
171
|
def recovery_codes(
|
170
172
|
user_id:
|
171
173
|
)
|
174
|
+
headers = {}
|
172
175
|
request = {
|
173
176
|
user_id: user_id
|
174
177
|
}
|
175
178
|
|
176
|
-
post_request('/v1/totps/recovery_codes', request)
|
179
|
+
post_request('/v1/totps/recovery_codes', request, headers)
|
177
180
|
end
|
178
181
|
|
179
182
|
# Authenticate a recovery code for a TOTP instance.
|
@@ -245,6 +248,7 @@ module Stytch
|
|
245
248
|
session_jwt: nil,
|
246
249
|
session_custom_claims: nil
|
247
250
|
)
|
251
|
+
headers = {}
|
248
252
|
request = {
|
249
253
|
user_id: user_id,
|
250
254
|
recovery_code: recovery_code
|
@@ -254,7 +258,7 @@ module Stytch
|
|
254
258
|
request[:session_jwt] = session_jwt unless session_jwt.nil?
|
255
259
|
request[:session_custom_claims] = session_custom_claims unless session_custom_claims.nil?
|
256
260
|
|
257
|
-
post_request('/v1/totps/recover', request)
|
261
|
+
post_request('/v1/totps/recover', request, headers)
|
258
262
|
end
|
259
263
|
end
|
260
264
|
end
|
data/lib/stytch/users.rb
CHANGED
@@ -77,6 +77,7 @@ module Stytch
|
|
77
77
|
trusted_metadata: nil,
|
78
78
|
untrusted_metadata: nil
|
79
79
|
)
|
80
|
+
headers = {}
|
80
81
|
request = {}
|
81
82
|
request[:email] = email unless email.nil?
|
82
83
|
request[:name] = name unless name.nil?
|
@@ -86,7 +87,7 @@ module Stytch
|
|
86
87
|
request[:trusted_metadata] = trusted_metadata unless trusted_metadata.nil?
|
87
88
|
request[:untrusted_metadata] = untrusted_metadata unless untrusted_metadata.nil?
|
88
89
|
|
89
|
-
post_request('/v1/users', request)
|
90
|
+
post_request('/v1/users', request, headers)
|
90
91
|
end
|
91
92
|
|
92
93
|
# Get information about a specific User.
|
@@ -114,7 +115,7 @@ module Stytch
|
|
114
115
|
# An array of phone number objects linked to the User.
|
115
116
|
# The type of this field is list of +PhoneNumber+ (+object+).
|
116
117
|
# webauthn_registrations::
|
117
|
-
# An array that contains a list of all WebAuthn registrations for a given User in the Stytch API.
|
118
|
+
# An array that contains a list of all Passkey or WebAuthn registrations for a given User in the Stytch API.
|
118
119
|
# The type of this field is list of +WebAuthnRegistration+ (+object+).
|
119
120
|
# providers::
|
120
121
|
# An array of OAuth `provider` objects linked to the User.
|
@@ -149,9 +150,10 @@ module Stytch
|
|
149
150
|
def get(
|
150
151
|
user_id:
|
151
152
|
)
|
153
|
+
headers = {}
|
152
154
|
query_params = {}
|
153
155
|
request = request_with_query_params("/v1/users/#{user_id}", query_params)
|
154
|
-
get_request(request)
|
156
|
+
get_request(request, headers)
|
155
157
|
end
|
156
158
|
|
157
159
|
# Search for Users within your Stytch Project. Submit an empty `query` in the request to return all Users.
|
@@ -186,17 +188,18 @@ module Stytch
|
|
186
188
|
limit: nil,
|
187
189
|
query: nil
|
188
190
|
)
|
191
|
+
headers = {}
|
189
192
|
request = {}
|
190
193
|
request[:cursor] = cursor unless cursor.nil?
|
191
194
|
request[:limit] = limit unless limit.nil?
|
192
195
|
request[:query] = query unless query.nil?
|
193
196
|
|
194
|
-
post_request('/v1/users/search', request)
|
197
|
+
post_request('/v1/users/search', request, headers)
|
195
198
|
end
|
196
199
|
|
197
200
|
# Update a User's attributes.
|
198
201
|
#
|
199
|
-
# **Note:** In order to add a new email address or phone number to an existing User object, pass the new email address or phone number into the respective `/send` endpoint for the authentication method of your choice. If you specify the existing User's `user_id` while calling the `/send` endpoint, the new email address or phone number will be added to the existing User object
|
202
|
+
# **Note:** In order to add a new email address or phone number to an existing User object, pass the new email address or phone number into the respective `/send` endpoint for the authentication method of your choice. If you specify the existing User's `user_id` while calling the `/send` endpoint, the new, unverified email address or phone number will be added to the existing User object. If the user successfully authenticates within 5 minutes of the `/send` request, the new email address or phone number will be marked as verified and remain permanently on the existing Stytch User. Otherwise, it will be removed from the User object, and any subsequent login requests using that phone number will create a new User. We require this process to guard against an account takeover vulnerability.
|
200
203
|
#
|
201
204
|
# == Parameters:
|
202
205
|
# user_id::
|
@@ -245,13 +248,14 @@ module Stytch
|
|
245
248
|
trusted_metadata: nil,
|
246
249
|
untrusted_metadata: nil
|
247
250
|
)
|
251
|
+
headers = {}
|
248
252
|
request = {}
|
249
253
|
request[:name] = name unless name.nil?
|
250
254
|
request[:attributes] = attributes unless attributes.nil?
|
251
255
|
request[:trusted_metadata] = trusted_metadata unless trusted_metadata.nil?
|
252
256
|
request[:untrusted_metadata] = untrusted_metadata unless untrusted_metadata.nil?
|
253
257
|
|
254
|
-
put_request("/v1/users/#{user_id}", request)
|
258
|
+
put_request("/v1/users/#{user_id}", request, headers)
|
255
259
|
end
|
256
260
|
|
257
261
|
# Exchange a user's email address or phone number for another.
|
@@ -292,11 +296,12 @@ module Stytch
|
|
292
296
|
email_address: nil,
|
293
297
|
phone_number: nil
|
294
298
|
)
|
299
|
+
headers = {}
|
295
300
|
request = {}
|
296
301
|
request[:email_address] = email_address unless email_address.nil?
|
297
302
|
request[:phone_number] = phone_number unless phone_number.nil?
|
298
303
|
|
299
|
-
put_request("/v1/users/#{user_id}/exchange_primary_factor", request)
|
304
|
+
put_request("/v1/users/#{user_id}/exchange_primary_factor", request, headers)
|
300
305
|
end
|
301
306
|
|
302
307
|
# Delete a User from Stytch.
|
@@ -320,7 +325,8 @@ module Stytch
|
|
320
325
|
def delete(
|
321
326
|
user_id:
|
322
327
|
)
|
323
|
-
|
328
|
+
headers = {}
|
329
|
+
delete_request("/v1/users/#{user_id}", headers)
|
324
330
|
end
|
325
331
|
|
326
332
|
# Delete an email from a User.
|
@@ -347,7 +353,8 @@ module Stytch
|
|
347
353
|
def delete_email(
|
348
354
|
email_id:
|
349
355
|
)
|
350
|
-
|
356
|
+
headers = {}
|
357
|
+
delete_request("/v1/users/emails/#{email_id}", headers)
|
351
358
|
end
|
352
359
|
|
353
360
|
# Delete a phone number from a User.
|
@@ -374,7 +381,8 @@ module Stytch
|
|
374
381
|
def delete_phone_number(
|
375
382
|
phone_id:
|
376
383
|
)
|
377
|
-
|
384
|
+
headers = {}
|
385
|
+
delete_request("/v1/users/phone_numbers/#{phone_id}", headers)
|
378
386
|
end
|
379
387
|
|
380
388
|
# Delete a WebAuthn registration from a User.
|
@@ -401,7 +409,8 @@ module Stytch
|
|
401
409
|
def delete_webauthn_registration(
|
402
410
|
webauthn_registration_id:
|
403
411
|
)
|
404
|
-
|
412
|
+
headers = {}
|
413
|
+
delete_request("/v1/users/webauthn_registrations/#{webauthn_registration_id}", headers)
|
405
414
|
end
|
406
415
|
|
407
416
|
# Delete a biometric registration from a User.
|
@@ -428,7 +437,8 @@ module Stytch
|
|
428
437
|
def delete_biometric_registration(
|
429
438
|
biometric_registration_id:
|
430
439
|
)
|
431
|
-
|
440
|
+
headers = {}
|
441
|
+
delete_request("/v1/users/biometric_registrations/#{biometric_registration_id}", headers)
|
432
442
|
end
|
433
443
|
|
434
444
|
# Delete a TOTP from a User.
|
@@ -455,7 +465,8 @@ module Stytch
|
|
455
465
|
def delete_totp(
|
456
466
|
totp_id:
|
457
467
|
)
|
458
|
-
|
468
|
+
headers = {}
|
469
|
+
delete_request("/v1/users/totps/#{totp_id}", headers)
|
459
470
|
end
|
460
471
|
|
461
472
|
# Delete a crypto wallet from a User.
|
@@ -482,7 +493,8 @@ module Stytch
|
|
482
493
|
def delete_crypto_wallet(
|
483
494
|
crypto_wallet_id:
|
484
495
|
)
|
485
|
-
|
496
|
+
headers = {}
|
497
|
+
delete_request("/v1/users/crypto_wallets/#{crypto_wallet_id}", headers)
|
486
498
|
end
|
487
499
|
|
488
500
|
# Delete a password from a User.
|
@@ -509,7 +521,8 @@ module Stytch
|
|
509
521
|
def delete_password(
|
510
522
|
password_id:
|
511
523
|
)
|
512
|
-
|
524
|
+
headers = {}
|
525
|
+
delete_request("/v1/users/passwords/#{password_id}", headers)
|
513
526
|
end
|
514
527
|
|
515
528
|
# Delete an OAuth registration from a User.
|
@@ -536,7 +549,8 @@ module Stytch
|
|
536
549
|
def delete_oauth_registration(
|
537
550
|
oauth_user_registration_id:
|
538
551
|
)
|
539
|
-
|
552
|
+
headers = {}
|
553
|
+
delete_request("/v1/users/oauth/#{oauth_user_registration_id}", headers)
|
540
554
|
end
|
541
555
|
end
|
542
556
|
end
|
data/lib/stytch/version.rb
CHANGED