stytch 6.4.0 → 6.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 94327b3a992f3e596ec4c0a5a6bad97d2c78041e15f12a470949819aa5c0994d
4
- data.tar.gz: a02935d82c7129002058f425f15d73886b5f373b9f942e35cfb410fd62c7148d
3
+ metadata.gz: b550936fb7076aad0eb10a1551f50440e8855c5042e6d1173a68d5eaf8df7b7d
4
+ data.tar.gz: afa5981979e47b49868ce2be6f701d3d94102365f2565e8f1c42889d548b8af5
5
5
  SHA512:
6
- metadata.gz: c366e0741c92ecf5ce5413beb57917a01f733ecc231540aebfab19c8a51ee75e7ee9deded5d23453b0580fc3556c90f7e2d1b707dfd79fa6aa6fa6b43cf5e152
7
- data.tar.gz: 9e2540999fa38c50436ea9409859cff663378d7b4a4d21a9ec15bdc8e36b326ed3ae2d681751739adbcecb57b3bd3a1c578394ba6d9dd2b92a1e9b5863f1a84b
6
+ metadata.gz: 48fb733f974b3f66b0f11d62aa0215ddf162f8d3f715d63c750e3820c261fffb33a1a04668370b66b28f2fb5d7311bd0608d3b6cc421d48629b93bb287dba814
7
+ data.tar.gz: 6f05e0e6dad871dd162c45007c2e9cf8a303b721d8a81aa1f74dfbe785f317cf14cabdeedfce2abe2d42523773e260998a372644c4fa8da7f1e362b3f186815c
@@ -26,3 +26,16 @@ jobs:
26
26
  bundler-cache: true
27
27
 
28
28
  - run: bundle exec rspec
29
+
30
+ lint:
31
+ runs-on: ubuntu-latest
32
+ steps:
33
+ - uses: actions/checkout@v3
34
+
35
+ - uses: ruby/setup-ruby@v1
36
+ with:
37
+ # Match the minimum supported Ruby version in the gemspec.
38
+ ruby-version: '2.7'
39
+ bundler-cache: true
40
+
41
+ - run: bundle exec rubocop
data/.rubocop.yml ADDED
@@ -0,0 +1,21 @@
1
+ require:
2
+ - rubocop-rspec
3
+
4
+ AllCops:
5
+ NewCops: disable
6
+ # The target Ruby version must match the one in stytch.gemspec.
7
+ TargetRubyVersion: 2.7
8
+
9
+ Layout/LineLength: { Enabled: false }
10
+
11
+ Metrics: { Enabled: false }
12
+
13
+ Style/Documentation: { Enabled: false }
14
+ Style/For: { Enabled: false }
15
+ Style/FrozenStringLiteralComment: { Enabled: false }
16
+ Style/NumericPredicate: { Enabled: false }
17
+ Style/StringConcatenation: { Enabled: false }
18
+
19
+ RSpec/DescribedClass: { Enabled: false }
20
+ RSpec/ExampleLength: { Enabled: false }
21
+ RSpec/MultipleExpectations: { Enabled: false }
data/DEVELOPMENT.md CHANGED
@@ -5,7 +5,9 @@ Thanks for contributing to Stytch's Ruby library! If you run into trouble, find
5
5
  ## Setup
6
6
 
7
7
  1. Clone this repo.
8
- 2. To test your changes locally, update your GEMFILE with `gem 'stytch', path: '../stytch'` where `../stytch` is the path to your cloned copy of stytch-ruby.
8
+ 2. Install development dependencies using [Bundler]: `bundle install`
9
+
10
+ To test your changes locally in another project, update your `GEMFILE` with `gem 'stytch', path: '../stytch'` where `../stytch` is the path to your cloned copy of stytch-ruby.
9
11
 
10
12
  ## Issues and Pull Requests
11
13
 
@@ -15,4 +17,5 @@ If you have non-trivial changes you'd like us to incorporate, please open an iss
15
17
 
16
18
  When you're ready for someone to look at your issue or PR, assign `@stytchauth/client-libraries` (GitHub should do this automatically). If we don't acknowledge it within one business day, please escalate it by tagging `@stytchauth/engineering` in a comment or letting us know in [Slack].
17
19
 
18
- [Slack]: https://join.slack.com/t/stytch/shared_invite/zt-nil4wo92-jApJ9Cl32cJbEd9esKkvyg
20
+ [Bundler]: https://bundler.io/
21
+ [Slack]: https://join.slack.com/t/stytch/shared_invite/zt-nil4wo92-jApJ9Cl32cJbEd9esKkvyg
@@ -31,7 +31,7 @@ module StytchB2B
31
31
  @organizations = StytchB2B::Organizations.new(@connection)
32
32
  @passwords = StytchB2B::Passwords.new(@connection)
33
33
  @sso = StytchB2B::SSO.new(@connection)
34
- @sessions = StytchB2B::Sessions.new(@connection)
34
+ @sessions = StytchB2B::Sessions.new(@connection, project_id)
35
35
  end
36
36
 
37
37
  private
@@ -280,10 +280,7 @@ module StytchB2B
280
280
  request[:trusted_metadata] = trusted_metadata unless trusted_metadata.nil?
281
281
  request[:sso_default_connection_id] = sso_default_connection_id unless sso_default_connection_id.nil?
282
282
  request[:sso_jit_provisioning] = sso_jit_provisioning unless sso_jit_provisioning.nil?
283
- unless sso_jit_provisioning_allowed_connections.nil?
284
- request[:sso_jit_provisioning_allowed_connections] =
285
- sso_jit_provisioning_allowed_connections
286
- end
283
+ request[:sso_jit_provisioning_allowed_connections] = sso_jit_provisioning_allowed_connections unless sso_jit_provisioning_allowed_connections.nil?
287
284
  request[:email_allowed_domains] = email_allowed_domains unless email_allowed_domains.nil?
288
285
  request[:email_jit_provisioning] = email_jit_provisioning unless email_jit_provisioning.nil?
289
286
  request[:email_invites] = email_invites unless email_invites.nil?
@@ -180,12 +180,9 @@ module StytchB2B
180
180
  post_request('/v1/b2b/passwords/migrate', request)
181
181
  end
182
182
 
183
- # Authenticate a member with their email address and password. This endpoint verifies that the member has a password currently set, and that the entered password is correct. There are two instances where the endpoint will return a reset_password error even if they enter their previous password:
184
- # * The member’s credentials appeared in the HaveIBeenPwned dataset.
185
- # * We force a password reset to ensure that the member is the legitimate owner of the email address, and not a malicious actor abusing the compromised credentials.
186
- # * A member that has previously authenticated with email/password uses a passwordless authentication method tied to the same email address (e.g. Magic Links) for the first time. Any subsequent email/password authentication attempt will result in this error.
187
- # * We force a password reset in this instance in order to safely deduplicate the account by email address, without introducing the risk of a pre-hijack account takeover attack.
188
- # * Imagine a bad actor creates many accounts using passwords and the known email addresses of their victims. If a victim comes to the site and logs in for the first time with an email-based passwordless authentication method then both the victim and the bad actor have credentials to access to the same account. To prevent this, any further email/password login attempts first require a password reset which can only be accomplished by someone with access to the underlying email address.
183
+ # Authenticate a member with their email address and password. This endpoint verifies that the member has a password currently set, and that the entered password is correct.
184
+ #
185
+ # If you have breach detection during authentication enabled in your [password strength policy](https://stytch.com/docs/b2b/guides/passwords/strength-policies) and the member's credentials have appeared in the HaveIBeenPwned dataset, this endpoint will return a `member_reset_password` error even if the member enters a correct password. We force a password reset in this case to ensure that the member is the legitimate owner of the email address and not a malicious actor abusing the compromised credentials.
189
186
  #
190
187
  # If the Member is required to complete MFA to log in to the Organization, the returned value of `member_authenticated` will be `false`, and an `intermediate_session_token` will be returned.
191
188
  # The `intermediate_session_token` can be passed into the [OTP SMS Authenticate endpoint](https://stytch.com/docs/b2b/api/authenticate-otp-sms) to complete the MFA step and acquire a full member session.
@@ -382,10 +379,7 @@ module StytchB2B
382
379
  email_address: email_address
383
380
  }
384
381
  request[:reset_password_redirect_url] = reset_password_redirect_url unless reset_password_redirect_url.nil?
385
- unless reset_password_expiration_minutes.nil?
386
- request[:reset_password_expiration_minutes] =
387
- reset_password_expiration_minutes
388
- end
382
+ request[:reset_password_expiration_minutes] = reset_password_expiration_minutes unless reset_password_expiration_minutes.nil?
389
383
  request[:code_challenge] = code_challenge unless code_challenge.nil?
390
384
  request[:login_redirect_url] = login_redirect_url unless login_redirect_url.nil?
391
385
  request[:locale] = locale unless locale.nil?
@@ -543,6 +537,32 @@ module StytchB2B
543
537
  # session_jwt::
544
538
  # The JSON Web Token (JWT) for a given Stytch Session.
545
539
  # The type of this field is nilable +String+.
540
+ # session_duration_minutes::
541
+ # Set the session lifetime to be this many minutes from now. This will start a new session if one doesn't already exist,
542
+ # returning both an opaque `session_token` and `session_jwt` for this session. Remember that the `session_jwt` will have a fixed lifetime of
543
+ # five minutes regardless of the underlying session duration, and will need to be refreshed over time.
544
+ #
545
+ # This value must be a minimum of 5 and a maximum of 527040 minutes (366 days).
546
+ #
547
+ # If a `session_token` or `session_jwt` is provided then a successful authentication will continue to extend the session this many minutes.
548
+ #
549
+ # If the `session_duration_minutes` parameter is not specified, a Stytch session will be created with a 60 minute duration. If you don't want
550
+ # to use the Stytch session product, you can ignore the session fields in the response.
551
+ # The type of this field is nilable +Integer+.
552
+ # session_custom_claims::
553
+ # Add a custom claims map to the Session being authenticated. Claims are only created if a Session is initialized by providing a value in
554
+ # `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
555
+ # delete a key, supply a null value. Custom claims made with reserved claims (`iss`, `sub`, `aud`, `exp`, `nbf`, `iat`, `jti`) will be ignored.
556
+ # Total custom claims size cannot exceed four kilobytes.
557
+ # The type of this field is nilable +object+.
558
+ # locale::
559
+ # Used to determine which language to use when sending the user this delivery method. Parameter is a [IETF BCP 47 language tag](https://www.w3.org/International/articles/language-tags/), e.g. `"en"`.
560
+ #
561
+ # Currently supported languages are English (`"en"`), Spanish (`"es"`), and Brazilian Portuguese (`"pt-br"`); if no value is provided, the copy defaults to English.
562
+ #
563
+ # Request support for additional languages [here](https://docs.google.com/forms/d/e/1FAIpQLScZSpAu_m2AmLXRT3F3kap-s_mcV6UTBitYn6CdyWP0-o7YjQ/viewform?usp=sf_link")!
564
+ #
565
+ # The type of this field is nilable +ResetRequestLocale+ (string enum).
546
566
  #
547
567
  # == Returns:
548
568
  # An object with the following fields:
@@ -558,17 +578,38 @@ module StytchB2B
558
578
  # organization::
559
579
  # The [Organization object](https://stytch.com/docs/b2b/api/organization-object).
560
580
  # The type of this field is +Organization+ (+object+).
581
+ # session_token::
582
+ # A secret token for a given Stytch Session.
583
+ # The type of this field is +String+.
584
+ # session_jwt::
585
+ # The JSON Web Token (JWT) for a given Stytch Session.
586
+ # The type of this field is +String+.
587
+ # intermediate_session_token::
588
+ # The Intermediate Session Token. This token does not necessarily belong to a specific instance of a Member, but represents a bag of factors that may be converted to a member session.
589
+ # The token can be used with the [OTP SMS Authenticate endpoint](https://stytch.com/docs/b2b/api/authenticate-otp-sms) to complete an MFA flow;
590
+ # the [Exchange Intermediate Session endpoint](https://stytch.com/docs/b2b/api/exchange-intermediate-session) to join a specific Organization that allows the factors represented by the intermediate session token;
591
+ # or the [Create Organization via Discovery endpoint](https://stytch.com/docs/b2b/api/create-organization-via-discovery) to create a new Organization and Member.
592
+ # The type of this field is +String+.
593
+ # member_authenticated::
594
+ # Indicates whether the Member is fully authenticated. If false, the Member needs to complete an MFA step to log in to the Organization.
595
+ # The type of this field is +Boolean+.
561
596
  # status_code::
562
597
  # The HTTP status code of the response. Stytch follows standard HTTP response status code patterns, e.g. 2XX values equate to success, 3XX values are redirects, 4XX are client errors, and 5XX are server errors.
563
598
  # The type of this field is +Integer+.
564
599
  # member_session::
565
600
  # The [Session object](https://stytch.com/docs/b2b/api/session-object).
566
601
  # The type of this field is nilable +MemberSession+ (+object+).
602
+ # mfa_required::
603
+ # Information about the MFA requirements of the Organization and the Member's options for fulfilling MFA.
604
+ # The type of this field is nilable +MfaRequired+ (+object+).
567
605
  def reset(
568
606
  organization_id:,
569
607
  password:,
570
608
  session_token: nil,
571
- session_jwt: nil
609
+ session_jwt: nil,
610
+ session_duration_minutes: nil,
611
+ session_custom_claims: nil,
612
+ locale: nil
572
613
  )
573
614
  request = {
574
615
  organization_id: organization_id,
@@ -576,6 +617,9 @@ module StytchB2B
576
617
  }
577
618
  request[:session_token] = session_token unless session_token.nil?
578
619
  request[:session_jwt] = session_jwt unless session_jwt.nil?
620
+ request[:session_duration_minutes] = session_duration_minutes unless session_duration_minutes.nil?
621
+ request[:session_custom_claims] = session_custom_claims unless session_custom_claims.nil?
622
+ request[:locale] = locale unless locale.nil?
579
623
 
580
624
  post_request('/v1/b2b/passwords/session/reset', request)
581
625
  end
@@ -6,14 +6,31 @@
6
6
  # or your changes may be overwritten later!
7
7
  # !!!
8
8
 
9
+ require 'jwt'
10
+ require 'json/jwt'
11
+ require_relative 'errors'
9
12
  require_relative 'request_helper'
10
13
 
11
14
  module StytchB2B
12
15
  class Sessions
13
16
  include Stytch::RequestHelper
14
17
 
15
- def initialize(connection)
18
+ def initialize(connection, project_id)
16
19
  @connection = connection
20
+
21
+ @project_id = project_id
22
+ @cache_last_update = 0
23
+ @jwks_loader = lambda do |options|
24
+ @cached_keys = nil if options[:invalidate] && @cache_last_update < Time.now.to_i - 300
25
+ @cached_keys ||= begin
26
+ @cache_last_update = Time.now.to_i
27
+ keys = []
28
+ get_jwks(project_id: @project_id)['keys'].each do |r|
29
+ keys << r
30
+ end
31
+ { keys: keys }
32
+ end
33
+ end
17
34
  end
18
35
 
19
36
  # Retrieves all active Sessions for a Member.
@@ -290,5 +307,92 @@ module StytchB2B
290
307
  request = request_with_query_params("/v1/b2b/sessions/jwks/#{project_id}", query_params)
291
308
  get_request(request)
292
309
  end
310
+
311
+ # MANUAL(Sessions::authenticate_jwt)(SERVICE_METHOD)
312
+ # ADDIMPORT: require 'jwt'
313
+ # ADDIMPORT: require 'json/jwt'
314
+ # ADDIMPORT: require_relative 'errors'
315
+
316
+ # Parse a JWT and verify the signature. If max_token_age_seconds is unset, call the API directly
317
+ # If max_token_age_seconds is set and the JWT was issued (based on the "iat" claim) less than
318
+ # max_token_age_seconds seconds ago, then just verify locally and don't call the API
319
+ # To force remote validation for all tokens, set max_token_age_seconds to 0 or call authenticate()
320
+ def authenticate_jwt(
321
+ session_jwt,
322
+ max_token_age_seconds: nil,
323
+ session_duration_minutes: nil,
324
+ session_custom_claims: nil
325
+ )
326
+ if max_token_age_seconds == 0
327
+ return authenticate(
328
+ session_jwt: session_jwt,
329
+ session_duration_minutes: session_duration_minutes,
330
+ session_custom_claims: session_custom_claims
331
+ )
332
+ end
333
+
334
+ decoded_jwt = authenticate_jwt_local(session_jwt)
335
+ iat_time = Time.at(decoded_jwt['iat']).to_datetime
336
+ if iat_time + max_token_age_seconds >= Time.now
337
+ session = marshal_jwt_into_session(decoded_jwt)
338
+ { 'session' => session }
339
+ else
340
+ authenticate(
341
+ session_jwt: session_jwt,
342
+ session_duration_minutes: session_duration_minutes,
343
+ session_custom_claims: session_custom_claims
344
+ )
345
+ end
346
+ rescue StandardError
347
+ # JWT could not be verified locally. Check with the Stytch API.
348
+ authenticate(
349
+ session_jwt: session_jwt,
350
+ session_duration_minutes: session_duration_minutes,
351
+ session_custom_claims: session_custom_claims
352
+ )
353
+ end
354
+
355
+ # Parse a JWT and verify the signature locally (without calling /authenticate in the API)
356
+ # Uses the cached value to get the JWK but if it is unavailable, it calls the get_jwks()
357
+ # function to get the JWK
358
+ # This method never authenticates a JWT directly with the API
359
+ def authenticate_jwt_local(session_jwt)
360
+ issuer = 'stytch.com/' + @project_id
361
+ begin
362
+ decoded_token = JWT.decode session_jwt, nil, true,
363
+ { jwks: @jwks_loader, iss: issuer, verify_iss: true, aud: @project_id, verify_aud: true, algorithms: ['RS256'] }
364
+ decoded_token[0]
365
+ rescue JWT::InvalidIssuerError
366
+ raise JWTInvalidIssuerError
367
+ rescue JWT::InvalidAudError
368
+ raise JWTInvalidAudienceError
369
+ rescue JWT::ExpiredSignature
370
+ raise JWTExpiredSignatureError
371
+ rescue JWT::IncorrectAlgorithm
372
+ raise JWTIncorrectAlgorithmError
373
+ end
374
+ end
375
+
376
+ def marshal_jwt_into_session(jwt)
377
+ stytch_claim = 'https://stytch.com/session'
378
+ expires_at = jwt[stytch_claim]['expires_at'] || Time.at(jwt['exp']).to_datetime.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
379
+ # The custom claim set is all the claims in the payload except for the standard claims and
380
+ # the Stytch session claim. The cleanest way to collect those seems to be naming what we want
381
+ # to omit and filtering the rest to collect the custom claims.
382
+ reserved_claims = ['aud', 'exp', 'iat', 'iss', 'jti', 'nbf', 'sub', stytch_claim]
383
+ custom_claims = jwt.reject { |key, _| reserved_claims.include?(key) }
384
+ {
385
+ 'session_id' => jwt[stytch_claim]['id'],
386
+ 'user_id' => jwt['sub'],
387
+ 'started_at' => jwt[stytch_claim]['started_at'],
388
+ 'last_accessed_at' => jwt[stytch_claim]['last_accessed_at'],
389
+ # For JWTs that include it, prefer the inner expires_at claim.
390
+ 'expires_at' => expires_at,
391
+ 'attributes' => jwt[stytch_claim]['attributes'],
392
+ 'authentication_factors' => jwt[stytch_claim]['authentication_factors'],
393
+ 'custom_claims' => custom_claims
394
+ }
395
+ end
396
+ # ENDMANUAL(Sessions::authenticate_jwt)
293
397
  end
294
398
  end
@@ -23,7 +23,11 @@ module Stytch
23
23
  #
24
24
  # == Parameters:
25
25
  # token::
26
- # The token to authenticate.
26
+ # The Magic Link `token` from the `?token=` query parameter in the URL.
27
+ #
28
+ # The redirect URL will look like `https://example.com/authenticate?stytch_token_type=magic_links&token=rM_kw42CWBhsHLF62V75jELMbvJ87njMe3tFVj7Qupu7`
29
+ #
30
+ # In the redirect URL, the `stytch_token_type` will be `magic_link`. See [here](https://stytch.com/docs/guides/dashboard/redirect-urls) for more detail.
27
31
  # The type of this field is +String+.
28
32
  # attributes::
29
33
  # Provided attributes help with fraud detection.
@@ -167,9 +171,7 @@ module Stytch
167
171
  # Send a magic link to an existing Stytch user using their email address. If you'd like to create a user and send them a magic link by email with one request, use our [log in or create endpoint](https://stytch.com/docs/api/log-in-or-create-user-by-email).
168
172
  #
169
173
  # ### Add an email to an existing user
170
- # This endpoint also allows you to add a new email to an existing Stytch User. Including a `user_id`, `session_token`, or `session_jwt` in the request will add the email to the pre-existing Stytch User upon successful authentication.
171
- #
172
- # Adding a new email to an existing Stytch User requires the user to be present and validate the email via magic link. This requirement is in place to prevent account takeover attacks.
174
+ # This endpoint also allows you to add a new email address to an existing Stytch User. Including a `user_id`, `session_token`, or `session_jwt` in your Send Magic Link by email request will add the new, unverified email address to the existing Stytch User. If the user successfully authenticates within 5 minutes, the new email address 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 email address will create a new User.
173
175
  #
174
176
  # ### Next steps
175
177
  # The user is emailed a magic link which redirects them to the provided [redirect URL](https://stytch.com/docs/guides/magic-links/email-magic-links/redirect-routing). Collect the `token` from the URL query parameters, and call [Authenticate magic link](https://stytch.com/docs/api/authenticate-magic-link) to complete authentication.
@@ -271,7 +273,7 @@ module Stytch
271
273
  # Send either a login or signup Magic Link to the User based on if the email is associated with a User already. A new or pending User will receive a signup Magic Link. An active User will receive a login Magic Link. For more information on how to control the status your Users are created in see the `create_user_as_pending` flag.
272
274
  #
273
275
  # ### Next steps
274
- # The User is emailed a Magic Link which redirects them to the provided [redirect URL](https://stytch.com/docs/magic-links#email-magic-links_redirect-routing). Collect the `token` from the URL query parameters and call [Authenticate Magic Link](https://stytch.com/docs/api/authenticate-magic-link) to complete authentication.
276
+ # The User is emailed a Magic Link which redirects them to the provided [redirect URL](https://stytch.com/docs/guides/magic-links/email-magic-links/redirect-routing). Collect the `token` from the URL query parameters and call [Authenticate Magic Link](https://stytch.com/docs/api/authenticate-magic-link) to complete authentication.
275
277
  #
276
278
  # == Parameters:
277
279
  # email::
@@ -367,7 +369,7 @@ module Stytch
367
369
  # Create a User and send an invite Magic Link to the provided `email`. The User will be created with a `pending` status until they click the Magic Link in the invite email.
368
370
  #
369
371
  # ### Next steps
370
- # The User is emailed a Magic Link which redirects them to the provided [redirect URL](https://stytch.com/docs/magic-links#email-magic-links_redirect-routing). Collect the `token` from the URL query parameters and call [Authenticate Magic Link](https://stytch.com/docs/api/authenticate-magic-link) to complete authentication.
372
+ # The User is emailed a Magic Link which redirects them to the provided [redirect URL](https://stytch.com/docs/guides/magic-links/email-magic-links/redirect-routing). Collect the `token` from the URL query parameters and call [Authenticate Magic Link](https://stytch.com/docs/api/authenticate-magic-link) to complete authentication.
371
373
  #
372
374
  # == Parameters:
373
375
  # email::
data/lib/stytch/oauth.rb CHANGED
@@ -67,7 +67,11 @@ module Stytch
67
67
  #
68
68
  # == Parameters:
69
69
  # token::
70
- # The token to authenticate.
70
+ # The OAuth `token` from the `?token=` query parameter in the URL.
71
+ #
72
+ # The redirect URL will look like `https://example.com/authenticate?stytch_token_type=oauth&token=rM_kw42CWBhsHLF62V75jELMbvJ87njMe3tFVj7Qupu7`
73
+ #
74
+ # In the redirect URL, the `stytch_token_type` will be `oauth`. See [here](https://stytch.com/docs/guides/dashboard/redirect-urls) for more detail.
71
75
  # The type of this field is +String+.
72
76
  # session_token::
73
77
  # Reuse an existing session instead of creating a new one. If you provide us with a `session_token`, then we'll update the session represented by this session token with this OAuth factor. If this `session_token` belongs to a different user than the OAuth token, the session_jwt will be ignored. This endpoint will error if both `session_token` and `session_jwt` are provided.
data/lib/stytch/otps.rb CHANGED
@@ -131,9 +131,7 @@ module Stytch
131
131
  #
132
132
  # ### Add a phone number to an existing user
133
133
  #
134
- # This endpoint also allows you to add a new phone number to an existing Stytch User. Including a `user_id`, `session_token`, or `session_jwt` in the request will add the phone number to the pre-existing Stytch User upon successful authentication.
135
- #
136
- # Adding a new phone number to an existing Stytch User requires the user to be present and validate the phone number via OTP. This requirement is in place to prevent account takeover attacks.
134
+ # This endpoint also allows you to add a new phone number to an existing Stytch User. Including a `user_id`, `session_token`, or `session_jwt` in your Send one-time passcode by SMS request will add the new, unverified phone number to the existing Stytch User. If the user successfully authenticates within 5 minutes, the new 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.
137
135
  #
138
136
  # ### Next steps
139
137
  #
@@ -289,9 +287,7 @@ module Stytch
289
287
  #
290
288
  # ### Add a phone number to an existing user
291
289
  #
292
- # This endpoint also allows you to add a new phone number to an existing Stytch User. Including a `user_id`, `session_token`, or `session_jwt` in the request will add the phone number to the pre-existing Stytch User upon successful authentication.
293
- #
294
- # Adding a new phone number to an existing Stytch User requires the user to be present and validate the phone number via OTP. This requirement is in place to prevent account takeover attacks.
290
+ # This endpoint also allows you to add a new phone number to an existing Stytch User. Including a `user_id`, `session_token`, or `session_jwt` in your Send one-time passcode by WhatsApp request will add the new, unverified phone number to the existing Stytch User. If the user successfully authenticates within 5 minutes, the new 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.
295
291
  #
296
292
  # ### Next steps
297
293
  #
@@ -442,9 +438,7 @@ module Stytch
442
438
  # Send a One-Time Passcode (OTP) to a User using their email. If you'd like to create a user and send them a passcode with one request, use our [log in or create endpoint](https://stytch.com/docs/api/log-in-or-create-user-by-email-otp).
443
439
  #
444
440
  # ### Add an email to an existing user
445
- # This endpoint also allows you to add a new email to an existing Stytch User. Including a `user_id`, `session_token`, or `session_jwt` in the request will add the email to the pre-existing Stytch User upon successful authentication.
446
- #
447
- # Adding a new email to an existing Stytch User requires the User to be present and validate the email via OTP. This requirement is in place to prevent account takeover attacks.
441
+ # This endpoint also allows you to add a new email address to an existing Stytch User. Including a `user_id`, `session_token`, or `session_jwt` in your Send one-time passcode by email request will add the new, unverified email address to the existing Stytch User. If the user successfully authenticates within 5 minutes, the new email address 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 email address will create a new User.
448
442
  #
449
443
  # ### Next steps
450
444
  # Collect the OTP which was delivered to the user. Call [Authenticate OTP](https://stytch.com/docs/api/authenticate-otp) using the OTP `code` along with the `phone_id` found in the response as the `method_id`.
@@ -419,10 +419,7 @@ module Stytch
419
419
  email: email
420
420
  }
421
421
  request[:reset_password_redirect_url] = reset_password_redirect_url unless reset_password_redirect_url.nil?
422
- unless reset_password_expiration_minutes.nil?
423
- request[:reset_password_expiration_minutes] =
424
- reset_password_expiration_minutes
425
- end
422
+ request[:reset_password_expiration_minutes] = reset_password_expiration_minutes unless reset_password_expiration_minutes.nil?
426
423
  request[:code_challenge] = code_challenge unless code_challenge.nil?
427
424
  request[:attributes] = attributes unless attributes.nil?
428
425
  request[:login_redirect_url] = login_redirect_url unless login_redirect_url.nil?
@@ -436,9 +433,15 @@ module Stytch
436
433
  #
437
434
  # The provided password needs to meet our password strength requirements, which can be checked in advance with the password strength endpoint. If the token and password are accepted, the password is securely stored for future authentication and the user is authenticated.
438
435
  #
436
+ # Note that a successful password reset by email will revoke all active sessions for the `user_id`.
437
+ #
439
438
  # == Parameters:
440
439
  # token::
441
- # The token to authenticate.
440
+ # The Passwords `token` from the `?token=` query parameter in the URL.
441
+ #
442
+ # In the redirect URL, the `stytch_token_type` will be `login` or `reset_password`.
443
+ #
444
+ # See examples and read more about redirect URLs [here](https://stytch.com/docs/guides/dashboard/redirect-urls).
442
445
  # The type of this field is +String+.
443
446
  # password::
444
447
  # The password of the user
@@ -537,6 +540,8 @@ module Stytch
537
540
 
538
541
  # Reset the User’s password using their existing password.
539
542
  #
543
+ # Note that a successful password reset via an existing password will revoke all active sessions for the `user_id`.
544
+ #
540
545
  # == Parameters:
541
546
  # email::
542
547
  # The email address of the end user.
@@ -628,6 +633,8 @@ module Stytch
628
633
 
629
634
  # Reset the user’s password using their existing session. The endpoint will error if the session does not have a password, email magic link, or email OTP authentication factor that has been issued within the last 5 minutes. This endpoint requires either a `session_jwt` or `session_token` be included in the request.
630
635
  #
636
+ # Note that a successful password reset via an existing session will revoke all active sessions for the `user_id`, except for the one used during the reset flow.
637
+ #
631
638
  # == Parameters:
632
639
  # password::
633
640
  # The password of the user
@@ -638,6 +645,22 @@ module Stytch
638
645
  # session_jwt::
639
646
  # The `session_jwt` associated with a User's existing Session.
640
647
  # The type of this field is nilable +String+.
648
+ # session_duration_minutes::
649
+ # Set the session lifetime to be this many minutes from now. This will start a new session if one doesn't already exist,
650
+ # returning both an opaque `session_token` and `session_jwt` for this session. Remember that the `session_jwt` will have a fixed lifetime of
651
+ # five minutes regardless of the underlying session duration, and will need to be refreshed over time.
652
+ #
653
+ # This value must be a minimum of 5 and a maximum of 527040 minutes (366 days).
654
+ #
655
+ # If a `session_token` or `session_jwt` is provided then a successful authentication will continue to extend the session this many minutes.
656
+ #
657
+ # If the `session_duration_minutes` parameter is not specified, a Stytch session will not be created.
658
+ # The type of this field is nilable +Integer+.
659
+ # session_custom_claims::
660
+ # 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.
661
+ #
662
+ # Custom claims made with reserved claims ("iss", "sub", "aud", "exp", "nbf", "iat", "jti") will be ignored. Total custom claims size cannot exceed four kilobytes.
663
+ # The type of this field is nilable +object+.
641
664
  #
642
665
  # == Returns:
643
666
  # An object with the following fields:
@@ -650,6 +673,12 @@ module Stytch
650
673
  # user::
651
674
  # 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.
652
675
  # The type of this field is +User+ (+object+).
676
+ # session_token::
677
+ # A secret token for a given Stytch Session.
678
+ # The type of this field is +String+.
679
+ # session_jwt::
680
+ # The JSON Web Token (JWT) for a given Stytch Session.
681
+ # The type of this field is +String+.
653
682
  # status_code::
654
683
  # The HTTP status code of the response. Stytch follows standard HTTP response status code patterns, e.g. 2XX values equate to success, 3XX values are redirects, 4XX are client errors, and 5XX are server errors.
655
684
  # The type of this field is +Integer+.
@@ -662,13 +691,17 @@ module Stytch
662
691
  def reset(
663
692
  password:,
664
693
  session_token: nil,
665
- session_jwt: nil
694
+ session_jwt: nil,
695
+ session_duration_minutes: nil,
696
+ session_custom_claims: nil
666
697
  )
667
698
  request = {
668
699
  password: password
669
700
  }
670
701
  request[:session_token] = session_token unless session_token.nil?
671
702
  request[:session_jwt] = session_jwt unless session_jwt.nil?
703
+ request[:session_duration_minutes] = session_duration_minutes unless session_duration_minutes.nil?
704
+ request[:session_custom_claims] = session_custom_claims unless session_custom_claims.nil?
672
705
 
673
706
  post_request('/v1/passwords/session/reset', request)
674
707
  end
data/lib/stytch/users.rb CHANGED
@@ -196,7 +196,7 @@ module Stytch
196
196
 
197
197
  # Update a User's attributes.
198
198
  #
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 upon successful authentication. We require this process to guard against an account takeover vulnerability.
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, 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
200
  #
201
201
  # == Parameters:
202
202
  # user_id::
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Stytch
4
- VERSION = '6.4.0'
4
+ VERSION = '6.5.1'
5
5
  end
data/stytch.gemspec CHANGED
@@ -30,4 +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'
34
+ spec.add_development_dependency 'rubocop-rspec', '2.24.0'
33
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: 6.4.0
4
+ version: 6.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - stytch
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-08-24 00:00:00.000000000 Z
11
+ date: 2023-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -72,6 +72,34 @@ dependencies:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
74
  version: 3.11.0
75
+ - !ruby/object:Gem::Dependency
76
+ name: rubocop
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - '='
80
+ - !ruby/object:Gem::Version
81
+ version: 1.56.3
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '='
87
+ - !ruby/object:Gem::Version
88
+ version: 1.56.3
89
+ - !ruby/object:Gem::Dependency
90
+ name: rubocop-rspec
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - '='
94
+ - !ruby/object:Gem::Version
95
+ version: 2.24.0
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - '='
101
+ - !ruby/object:Gem::Version
102
+ version: 2.24.0
75
103
  description:
76
104
  email:
77
105
  - support@stytch.com
@@ -84,6 +112,7 @@ files:
84
112
  - ".github/workflows/ruby.yml"
85
113
  - ".gitignore"
86
114
  - ".rspec"
115
+ - ".rubocop.yml"
87
116
  - ".travis.yml"
88
117
  - CODEOWNERS
89
118
  - CODE_OF_CONDUCT.md