stytch 6.4.0 → 7.2.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.
@@ -6,14 +6,32 @@
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, policy_cache)
16
19
  @connection = connection
20
+
21
+ @policy_cache = policy_cache
22
+ @project_id = project_id
23
+ @cache_last_update = 0
24
+ @jwks_loader = lambda do |options|
25
+ @cached_keys = nil if options[:invalidate] && @cache_last_update < Time.now.to_i - 300
26
+ @cached_keys ||= begin
27
+ @cache_last_update = Time.now.to_i
28
+ keys = []
29
+ get_jwks(project_id: @project_id)['keys'].each do |r|
30
+ keys << r
31
+ end
32
+ { keys: keys }
33
+ end
34
+ end
17
35
  end
18
36
 
19
37
  # Retrieves all active Sessions for a Member.
@@ -41,18 +59,26 @@ module StytchB2B
41
59
  organization_id:,
42
60
  member_id:
43
61
  )
62
+ headers = {}
44
63
  query_params = {
45
64
  organization_id: organization_id,
46
65
  member_id: member_id
47
66
  }
48
67
  request = request_with_query_params('/v1/b2b/sessions', query_params)
49
- get_request(request)
68
+ get_request(request, headers)
50
69
  end
51
70
 
52
71
  # Authenticates a Session and updates its lifetime by the specified `session_duration_minutes`. If the `session_duration_minutes` is not specified, a Session will not be extended. This endpoint requires either a `session_jwt` or `session_token` be included in the request. It will return an error if both are present.
53
72
  #
54
73
  # 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.
55
74
  #
75
+ # If an `authorization_check` object is passed in, this method will also check if the Member is authorized to perform the given action on the given Resource in the specified Organization. A Member is authorized if their Member Session contains a Role, assigned [explicitly or implicitly](https://stytch.com/docs/b2b/guides/rbac/role-assignment), with adequate permissions.
76
+ # In addition, the `organization_id` passed in the authorization check must match the Member's Organization.
77
+ #
78
+ # If the Member is not authorized to perform the specified action on the specified Resource, or if the
79
+ # `organization_id` does not match the Member's Organization, a 403 error will be thrown.
80
+ # Otherwise, the response will contain a list of Roles that satisfied the authorization check.
81
+ #
56
82
  # == Parameters:
57
83
  # session_token::
58
84
  # A secret token for a given Stytch Session.
@@ -78,6 +104,21 @@ module StytchB2B
78
104
  # delete a key, supply a null value. Custom claims made with reserved claims (`iss`, `sub`, `aud`, `exp`, `nbf`, `iat`, `jti`) will be ignored.
79
105
  # Total custom claims size cannot exceed four kilobytes.
80
106
  # The type of this field is nilable +object+.
107
+ # authorization_check::
108
+ # If an `authorization_check` object is passed in, this endpoint will also check if the Member is
109
+ # authorized to perform the given action on the given Resource in the specified Organization. A Member is authorized if
110
+ # their Member Session contains a Role, assigned
111
+ # [explicitly or implicitly](https://stytch.com/docs/b2b/guides/rbac/role-assignment), with adequate permissions.
112
+ # In addition, the `organization_id` passed in the authorization check must match the Member's Organization.
113
+ #
114
+ # The Roles on the Member Session may differ from the Roles you see on the Member object - Roles that are implicitly
115
+ # assigned by SSO connection or SSO group will only be valid for a Member Session if there is at least one authentication
116
+ # factor on the Member Session from the specified SSO connection.
117
+ #
118
+ # If the Member is not authorized to perform the specified action on the specified Resource, or if the
119
+ # `organization_id` does not match the Member's Organization, a 403 error will be thrown.
120
+ # Otherwise, the response will contain a list of Roles that satisfied the authorization check.
121
+ # The type of this field is nilable +AuthorizationCheck+ (+object+).
81
122
  #
82
123
  # == Returns:
83
124
  # An object with the following fields:
@@ -102,19 +143,26 @@ module StytchB2B
102
143
  # status_code::
103
144
  # 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.
104
145
  # The type of this field is +Integer+.
146
+ # verdict::
147
+ # If an `authorization_check` is provided in the request and the check succeeds, this field will return
148
+ # the complete list of Roles that gave the Member permission to perform the specified action on the specified Resource.
149
+ # The type of this field is nilable +AuthorizationVerdict+ (+object+).
105
150
  def authenticate(
106
151
  session_token: nil,
107
152
  session_duration_minutes: nil,
108
153
  session_jwt: nil,
109
- session_custom_claims: nil
154
+ session_custom_claims: nil,
155
+ authorization_check: nil
110
156
  )
157
+ headers = {}
111
158
  request = {}
112
159
  request[:session_token] = session_token unless session_token.nil?
113
160
  request[:session_duration_minutes] = session_duration_minutes unless session_duration_minutes.nil?
114
161
  request[:session_jwt] = session_jwt unless session_jwt.nil?
115
162
  request[:session_custom_claims] = session_custom_claims unless session_custom_claims.nil?
163
+ request[:authorization_check] = authorization_check unless authorization_check.nil?
116
164
 
117
- post_request('/v1/b2b/sessions/authenticate', request)
165
+ post_request('/v1/b2b/sessions/authenticate', request, headers)
118
166
  end
119
167
 
120
168
  # Revoke a Session and immediately invalidate all its tokens. To revoke a specific Session, pass either the `member_session_id`, `session_token`, or `session_jwt`. To revoke all Sessions for a Member, pass the `member_id`.
@@ -147,13 +195,14 @@ module StytchB2B
147
195
  session_jwt: nil,
148
196
  member_id: nil
149
197
  )
198
+ headers = {}
150
199
  request = {}
151
200
  request[:member_session_id] = member_session_id unless member_session_id.nil?
152
201
  request[:session_token] = session_token unless session_token.nil?
153
202
  request[:session_jwt] = session_jwt unless session_jwt.nil?
154
203
  request[:member_id] = member_id unless member_id.nil?
155
204
 
156
- post_request('/v1/b2b/sessions/revoke', request)
205
+ post_request('/v1/b2b/sessions/revoke', request, headers)
157
206
  end
158
207
 
159
208
  # Use this endpoint to exchange a Member's existing session for another session in a different Organization. This can be used to accept an invite, but not to create a new member via domain matching.
@@ -253,6 +302,7 @@ module StytchB2B
253
302
  session_custom_claims: nil,
254
303
  locale: nil
255
304
  )
305
+ headers = {}
256
306
  request = {
257
307
  organization_id: organization_id
258
308
  }
@@ -262,11 +312,19 @@ module StytchB2B
262
312
  request[:session_custom_claims] = session_custom_claims unless session_custom_claims.nil?
263
313
  request[:locale] = locale unless locale.nil?
264
314
 
265
- post_request('/v1/b2b/sessions/exchange', request)
315
+ post_request('/v1/b2b/sessions/exchange', request, headers)
266
316
  end
267
317
 
268
318
  # Get the JSON Web Key Set (JWKS) for a project.
269
319
  #
320
+ # 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.
321
+ #
322
+ # 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.
323
+ #
324
+ # If you're using one of our [backend SDKs](https://stytch.com/docs/b2b/sdks), the JWKS roll will be handled for you.
325
+ #
326
+ # 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.
327
+ #
270
328
  # == Parameters:
271
329
  # project_id::
272
330
  # The `project_id` to get the JWKS for.
@@ -286,9 +344,131 @@ module StytchB2B
286
344
  def get_jwks(
287
345
  project_id:
288
346
  )
347
+ headers = {}
289
348
  query_params = {}
290
349
  request = request_with_query_params("/v1/b2b/sessions/jwks/#{project_id}", query_params)
291
- get_request(request)
350
+ get_request(request, headers)
351
+ end
352
+
353
+ # MANUAL(Sessions::authenticate_jwt)(SERVICE_METHOD)
354
+ # ADDIMPORT: require 'jwt'
355
+ # ADDIMPORT: require 'json/jwt'
356
+ # ADDIMPORT: require_relative 'errors'
357
+
358
+ # Parse a JWT and verify the signature. If max_token_age_seconds is unset, call the API directly
359
+ # If max_token_age_seconds is set and the JWT was issued (based on the "iat" claim) less than
360
+ # max_token_age_seconds seconds ago, then just verify locally and don't call the API
361
+ # To force remote validation for all tokens, set max_token_age_seconds to 0 or call authenticate()
362
+ # Note that the 'user_id' field of the returned session is DEPRECATED: Use member_id instead
363
+ # This field will be removed in a future MAJOR release.
364
+ # If max_token_age_seconds is not supplied 300 seconds will be used as the default.
365
+ def authenticate_jwt(
366
+ session_jwt,
367
+ max_token_age_seconds: nil,
368
+ session_duration_minutes: nil,
369
+ session_custom_claims: nil,
370
+ authorization_check: nil
371
+ )
372
+ max_token_age_seconds = 300 if max_token_age_seconds.nil?
373
+
374
+ if max_token_age_seconds == 0
375
+ return authenticate(
376
+ session_jwt: session_jwt,
377
+ session_duration_minutes: session_duration_minutes,
378
+ session_custom_claims: session_custom_claims,
379
+ authorization_check: authorization_check
380
+ )
381
+ end
382
+
383
+ decoded_jwt = authenticate_jwt_local(session_jwt, max_token_age_seconds: max_token_age_seconds, authorization_check: authorization_check)
384
+ return decoded_jwt unless decoded_jwt.nil?
385
+
386
+ authenticate(
387
+ session_jwt: session_jwt,
388
+ session_duration_minutes: session_duration_minutes,
389
+ session_custom_claims: session_custom_claims,
390
+ authorization_check: authorization_check
391
+ )
392
+ rescue StandardError
393
+ # JWT could not be verified locally. Check with the Stytch API.
394
+ authenticate(
395
+ session_jwt: session_jwt,
396
+ session_duration_minutes: session_duration_minutes,
397
+ session_custom_claims: session_custom_claims,
398
+ authorization_check: authorization_check
399
+ )
400
+ end
401
+
402
+ # Parse a JWT and verify the signature locally (without calling /authenticate in the API)
403
+ # Uses the cached value to get the JWK but if it is unavailable, it calls the get_jwks()
404
+ # function to get the JWK
405
+ # This method never authenticates a JWT directly with the API
406
+ # If max_token_age_seconds is not supplied 300 seconds will be used as the default.
407
+ def authenticate_jwt_local(session_jwt, max_token_age_seconds: nil, authorization_check: nil)
408
+ max_token_age_seconds = 300 if max_token_age_seconds.nil?
409
+
410
+ issuer = 'stytch.com/' + @project_id
411
+ begin
412
+ decoded_token = JWT.decode session_jwt, nil, true,
413
+ { jwks: @jwks_loader, iss: issuer, verify_iss: true, aud: @project_id, verify_aud: true, algorithms: ['RS256'] }
414
+
415
+ session = decoded_token[0]
416
+ iat_time = Time.at(session['iat']).to_datetime
417
+ return nil unless iat_time + max_token_age_seconds >= Time.now
418
+
419
+ session = marshal_jwt_into_session(session)
420
+ rescue JWT::InvalidIssuerError
421
+ raise Stytch::JWTInvalidIssuerError
422
+ rescue JWT::InvalidAudError
423
+ raise Stytch::JWTInvalidAudienceError
424
+ rescue JWT::ExpiredSignature
425
+ raise Stytch::JWTExpiredSignatureError
426
+ rescue JWT::IncorrectAlgorithm
427
+ raise Stytch::JWTIncorrectAlgorithmError
428
+ end
429
+
430
+ # Do the auth check - intentionally don't rescue errors from here
431
+ if authorization_check && session['roles']
432
+ @policy_cache.perform_authorization_check(
433
+ subject_roles: session['roles'],
434
+ subject_org_id: session['member_session']['organization_id'],
435
+ authorization_check: authorization_check
436
+ )
437
+ end
438
+
439
+ session
440
+ end
441
+
442
+ # Note that the 'user_id' field is DEPRECATED: Use member_id instead
443
+ # This field will be removed in a future MAJOR release.
444
+ def marshal_jwt_into_session(jwt)
445
+ stytch_claim = 'https://stytch.com/session'
446
+ organization_claim = 'https://stytch.com/organization'
447
+
448
+ expires_at = jwt[stytch_claim]['expires_at'] || Time.at(jwt['exp']).to_datetime.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
449
+ # The custom claim set is all the claims in the payload except for the standard claims and
450
+ # the Stytch session claim. The cleanest way to collect those seems to be naming what we want
451
+ # to omit and filtering the rest to collect the custom claims.
452
+ reserved_claims = ['aud', 'exp', 'iat', 'iss', 'jti', 'nbf', 'sub', stytch_claim, organization_claim]
453
+ custom_claims = jwt.reject { |key, _| reserved_claims.include?(key) }
454
+ {
455
+ 'member_session' => {
456
+ 'session_id' => jwt[stytch_claim]['id'],
457
+ 'organization_id' => jwt[organization_claim]['organization_id'],
458
+ 'member_id' => jwt['sub'],
459
+ # DEPRECATED: Use member_id instead
460
+ 'user_id' => jwt['sub'],
461
+ 'started_at' => jwt[stytch_claim]['started_at'],
462
+ 'last_accessed_at' => jwt[stytch_claim]['last_accessed_at'],
463
+ # For JWTs that include it, prefer the inner expires_at claim.
464
+ 'expires_at' => expires_at,
465
+ 'attributes' => jwt[stytch_claim]['attributes'],
466
+ 'authentication_factors' => jwt[stytch_claim]['authentication_factors'],
467
+ 'custom_claims' => custom_claims
468
+ },
469
+ 'roles' => jwt[stytch_claim]['roles']
470
+ }
292
471
  end
472
+ # ENDMANUAL(Sessions::authenticate_jwt)
293
473
  end
294
474
  end
@@ -9,6 +9,44 @@
9
9
  require_relative 'request_helper'
10
10
 
11
11
  module StytchB2B
12
+ class GetConnectionsRequestOptions
13
+ # Optional authorization object.
14
+ # Pass in an active Stytch Member session token or session JWT and the request
15
+ # will be run using that member's permissions.
16
+ attr_accessor :authorization
17
+
18
+ def initialize(
19
+ authorization: nil
20
+ )
21
+ @authorization = authorization
22
+ end
23
+
24
+ def to_headers
25
+ headers = {}
26
+ headers.merge!(@authorization.to_headers) if authorization
27
+ headers
28
+ end
29
+ end
30
+
31
+ class DeleteConnectionRequestOptions
32
+ # Optional authorization object.
33
+ # Pass in an active Stytch Member session token or session JWT and the request
34
+ # will be run using that member's permissions.
35
+ attr_accessor :authorization
36
+
37
+ def initialize(
38
+ authorization: nil
39
+ )
40
+ @authorization = authorization
41
+ end
42
+
43
+ def to_headers
44
+ headers = {}
45
+ headers.merge!(@authorization.to_headers) if authorization
46
+ headers
47
+ end
48
+ end
49
+
12
50
  class SSO
13
51
  include Stytch::RequestHelper
14
52
  attr_reader :oidc, :saml
@@ -20,7 +58,7 @@ module StytchB2B
20
58
  @saml = StytchB2B::SSO::SAML.new(@connection)
21
59
  end
22
60
 
23
- # Get all SSO Connections owned by the organization.
61
+ # Get all SSO Connections owned by the organization. /%}
24
62
  #
25
63
  # == Parameters:
26
64
  # organization_id::
@@ -41,15 +79,21 @@ module StytchB2B
41
79
  # status_code::
42
80
  # 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.
43
81
  # The type of this field is +Integer+.
82
+ #
83
+ # == Method Options:
84
+ # This method supports an optional +GetConnectionsRequestOptions+ object which will modify the headers sent in the HTTP request.
44
85
  def get_connections(
45
- organization_id:
86
+ organization_id:,
87
+ method_options: nil
46
88
  )
89
+ headers = {}
90
+ headers = headers.merge(method_options.to_headers) unless method_options.nil?
47
91
  query_params = {}
48
92
  request = request_with_query_params("/v1/b2b/sso/#{organization_id}", query_params)
49
- get_request(request)
93
+ get_request(request, headers)
50
94
  end
51
95
 
52
- # Delete an existing SSO connection.
96
+ # Delete an existing SSO connection. /%}
53
97
  #
54
98
  # == Parameters:
55
99
  # organization_id::
@@ -70,11 +114,17 @@ module StytchB2B
70
114
  # status_code::
71
115
  # 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.
72
116
  # The type of this field is +Integer+.
117
+ #
118
+ # == Method Options:
119
+ # This method supports an optional +DeleteConnectionRequestOptions+ object which will modify the headers sent in the HTTP request.
73
120
  def delete_connection(
74
121
  organization_id:,
75
- connection_id:
122
+ connection_id:,
123
+ method_options: nil
76
124
  )
77
- delete_request("/v1/b2b/sso/#{organization_id}/connections/#{connection_id}")
125
+ headers = {}
126
+ headers = headers.merge(method_options.to_headers) unless method_options.nil?
127
+ delete_request("/v1/b2b/sso/#{organization_id}/connections/#{connection_id}", headers)
78
128
  end
79
129
 
80
130
  # Authenticate a user given a token.
@@ -184,6 +234,7 @@ module StytchB2B
184
234
  session_custom_claims: nil,
185
235
  locale: nil
186
236
  )
237
+ headers = {}
187
238
  request = {
188
239
  sso_token: sso_token
189
240
  }
@@ -194,7 +245,7 @@ module StytchB2B
194
245
  request[:session_custom_claims] = session_custom_claims unless session_custom_claims.nil?
195
246
  request[:locale] = locale unless locale.nil?
196
247
 
197
- post_request('/v1/b2b/sso/authenticate', request)
248
+ post_request('/v1/b2b/sso/authenticate', request, headers)
198
249
  end
199
250
 
200
251
  class OIDC
@@ -204,7 +255,7 @@ module StytchB2B
204
255
  @connection = connection
205
256
  end
206
257
 
207
- # Create a new OIDC Connection.
258
+ # Create a new OIDC Connection. /%}
208
259
  #
209
260
  # == Parameters:
210
261
  # organization_id::
@@ -225,14 +276,20 @@ module StytchB2B
225
276
  # connection::
226
277
  # The `OIDC Connection` object affected by this API call. See the [OIDC Connection Object](https://stytch.com/docs/b2b/api/oidc-connection-object) for complete response field details.
227
278
  # The type of this field is nilable +OIDCConnection+ (+object+).
279
+ #
280
+ # == Method Options:
281
+ # This method supports an optional +CreateConnectionRequestOptions+ object which will modify the headers sent in the HTTP request.
228
282
  def create_connection(
229
283
  organization_id:,
230
- display_name: nil
284
+ display_name: nil,
285
+ method_options: nil
231
286
  )
287
+ headers = {}
288
+ headers = headers.merge(method_options.to_headers) unless method_options.nil?
232
289
  request = {}
233
290
  request[:display_name] = display_name unless display_name.nil?
234
291
 
235
- post_request("/v1/b2b/sso/oidc/#{organization_id}", request)
292
+ post_request("/v1/b2b/sso/oidc/#{organization_id}", request, headers)
236
293
  end
237
294
 
238
295
  # Updates an existing OIDC connection.
@@ -253,6 +310,7 @@ module StytchB2B
253
310
  # * `token_url`
254
311
  # * `userinfo_url`
255
312
  # * `jwks_url`
313
+ # /%}
256
314
  #
257
315
  # == Parameters:
258
316
  # organization_id::
@@ -300,6 +358,9 @@ module StytchB2B
300
358
  # warning::
301
359
  # If it is not possible to resolve the well-known metadata document from the OIDC issuer, this field will explain what went wrong if the request is successful otherwise. In other words, even if the overall request succeeds, there could be relevant warnings related to the connection update.
302
360
  # The type of this field is nilable +String+.
361
+ #
362
+ # == Method Options:
363
+ # This method supports an optional +UpdateConnectionRequestOptions+ object which will modify the headers sent in the HTTP request.
303
364
  def update_connection(
304
365
  organization_id:,
305
366
  connection_id:,
@@ -310,8 +371,11 @@ module StytchB2B
310
371
  authorization_url: nil,
311
372
  token_url: nil,
312
373
  userinfo_url: nil,
313
- jwks_url: nil
374
+ jwks_url: nil,
375
+ method_options: nil
314
376
  )
377
+ headers = {}
378
+ headers = headers.merge(method_options.to_headers) unless method_options.nil?
315
379
  request = {}
316
380
  request[:display_name] = display_name unless display_name.nil?
317
381
  request[:client_id] = client_id unless client_id.nil?
@@ -322,7 +386,7 @@ module StytchB2B
322
386
  request[:userinfo_url] = userinfo_url unless userinfo_url.nil?
323
387
  request[:jwks_url] = jwks_url unless jwks_url.nil?
324
388
 
325
- put_request("/v1/b2b/sso/oidc/#{organization_id}/connections/#{connection_id}", request)
389
+ put_request("/v1/b2b/sso/oidc/#{organization_id}/connections/#{connection_id}", request, headers)
326
390
  end
327
391
  end
328
392
 
@@ -333,7 +397,7 @@ module StytchB2B
333
397
  @connection = connection
334
398
  end
335
399
 
336
- # Create a new SAML Connection.
400
+ # Create a new SAML Connection. /%}
337
401
  #
338
402
  # == Parameters:
339
403
  # organization_id::
@@ -354,14 +418,20 @@ module StytchB2B
354
418
  # connection::
355
419
  # The `SAML Connection` object affected by this API call. See the [SAML Connection Object](https://stytch.com/docs/b2b/api/saml-connection-object) for complete response field details.
356
420
  # The type of this field is nilable +SAMLConnection+ (+object+).
421
+ #
422
+ # == Method Options:
423
+ # This method supports an optional +CreateConnectionRequestOptions+ object which will modify the headers sent in the HTTP request.
357
424
  def create_connection(
358
425
  organization_id:,
359
- display_name: nil
426
+ display_name: nil,
427
+ method_options: nil
360
428
  )
429
+ headers = {}
430
+ headers = headers.merge(method_options.to_headers) unless method_options.nil?
361
431
  request = {}
362
432
  request[:display_name] = display_name unless display_name.nil?
363
433
 
364
- post_request("/v1/b2b/sso/saml/#{organization_id}", request)
434
+ post_request("/v1/b2b/sso/saml/#{organization_id}", request, headers)
365
435
  end
366
436
 
367
437
  # Updates an existing SAML connection.
@@ -371,6 +441,7 @@ module StytchB2B
371
441
  # * `attribute_mapping`
372
442
  # * `idp_entity_id`
373
443
  # * `x509_certificate`
444
+ # /%}
374
445
  #
375
446
  # == Parameters:
376
447
  # organization_id::
@@ -394,6 +465,20 @@ module StytchB2B
394
465
  # idp_sso_url::
395
466
  # The URL for which assertions for login requests will be sent. This will be provided by the IdP.
396
467
  # The type of this field is nilable +String+.
468
+ # saml_connection_implicit_role_assignments::
469
+ # All Members who log in with this SAML connection will implicitly receive the specified Roles. See the [RBAC guide](https://stytch.com/docs/b2b/guides/rbac/role-assignment) for more information about role assignment.
470
+ # The type of this field is nilable list of +String+.
471
+ # saml_group_implicit_role_assignments::
472
+ # Defines the names of the SAML groups
473
+ # that grant specific role assignments. For each group-Role pair, if a Member logs in with this SAML connection and
474
+ # belongs to the specified SAML group, they will be granted the associated Role. See the
475
+ # [RBAC guide](https://stytch.com/docs/b2b/guides/rbac/role-assignment) for more information about role assignment.
476
+ # Before adding any group implicit role assignments, you must add a "groups" key to your SAML connection's
477
+ # `attribute_mapping`. Make sure that your IdP is configured to correctly send the group information.
478
+ # The type of this field is nilable list of +String+.
479
+ # alternative_audience_uri::
480
+ # An alternative URL to use for the Audience Restriction. This value can be used when you wish to migrate an existing SAML integration to Stytch with zero downtime.
481
+ # The type of this field is nilable +String+.
397
482
  #
398
483
  # == Returns:
399
484
  # An object with the following fields:
@@ -406,6 +491,9 @@ module StytchB2B
406
491
  # connection::
407
492
  # The `SAML Connection` object affected by this API call. See the [SAML Connection Object](https://stytch.com/docs/b2b/api/saml-connection-object) for complete response field details.
408
493
  # The type of this field is nilable +SAMLConnection+ (+object+).
494
+ #
495
+ # == Method Options:
496
+ # This method supports an optional +UpdateConnectionRequestOptions+ object which will modify the headers sent in the HTTP request.
409
497
  def update_connection(
410
498
  organization_id:,
411
499
  connection_id:,
@@ -413,21 +501,80 @@ module StytchB2B
413
501
  display_name: nil,
414
502
  attribute_mapping: nil,
415
503
  x509_certificate: nil,
416
- idp_sso_url: nil
504
+ idp_sso_url: nil,
505
+ saml_connection_implicit_role_assignments: nil,
506
+ saml_group_implicit_role_assignments: nil,
507
+ alternative_audience_uri: nil,
508
+ method_options: nil
417
509
  )
510
+ headers = {}
511
+ headers = headers.merge(method_options.to_headers) unless method_options.nil?
418
512
  request = {}
419
513
  request[:idp_entity_id] = idp_entity_id unless idp_entity_id.nil?
420
514
  request[:display_name] = display_name unless display_name.nil?
421
515
  request[:attribute_mapping] = attribute_mapping unless attribute_mapping.nil?
422
516
  request[:x509_certificate] = x509_certificate unless x509_certificate.nil?
423
517
  request[:idp_sso_url] = idp_sso_url unless idp_sso_url.nil?
518
+ request[:saml_connection_implicit_role_assignments] = saml_connection_implicit_role_assignments unless saml_connection_implicit_role_assignments.nil?
519
+ request[:saml_group_implicit_role_assignments] = saml_group_implicit_role_assignments unless saml_group_implicit_role_assignments.nil?
520
+ request[:alternative_audience_uri] = alternative_audience_uri unless alternative_audience_uri.nil?
424
521
 
425
- put_request("/v1/b2b/sso/saml/#{organization_id}/connections/#{connection_id}", request)
522
+ put_request("/v1/b2b/sso/saml/#{organization_id}/connections/#{connection_id}", request, headers)
523
+ end
524
+
525
+ # Used to update an existing SAML connection using an IDP metadata URL.
526
+ #
527
+ # A newly created connection will not become active until all the following are provided:
528
+ # * `idp_sso_url`
529
+ # * `idp_entity_id`
530
+ # * `x509_certificate`
531
+ # * `attribute_mapping` (must be supplied using [Update SAML Connection](update-saml-connection))
532
+ # /%}
533
+ #
534
+ # == Parameters:
535
+ # organization_id::
536
+ # Globally unique UUID that identifies a specific Organization. The `organization_id` is critical to perform operations on an Organization, so be sure to preserve this value.
537
+ # The type of this field is +String+.
538
+ # connection_id::
539
+ # Globally unique UUID that identifies a specific SSO `connection_id` for a Member.
540
+ # The type of this field is +String+.
541
+ # metadata_url::
542
+ # A URL that points to the IdP metadata. This will be provided by the IdP.
543
+ # The type of this field is +String+.
544
+ #
545
+ # == Returns:
546
+ # An object with the following fields:
547
+ # request_id::
548
+ # 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.
549
+ # The type of this field is +String+.
550
+ # status_code::
551
+ # 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.
552
+ # The type of this field is +Integer+.
553
+ # connection::
554
+ # The `SAML Connection` object affected by this API call. See the [SAML Connection Object](https://stytch.com/docs/b2b/api/saml-connection-object) for complete response field details.
555
+ # The type of this field is nilable +SAMLConnection+ (+object+).
556
+ #
557
+ # == Method Options:
558
+ # This method supports an optional +UpdateByURLRequestOptions+ object which will modify the headers sent in the HTTP request.
559
+ def update_by_url(
560
+ organization_id:,
561
+ connection_id:,
562
+ metadata_url:,
563
+ method_options: nil
564
+ )
565
+ headers = {}
566
+ headers = headers.merge(method_options.to_headers) unless method_options.nil?
567
+ request = {
568
+ metadata_url: metadata_url
569
+ }
570
+
571
+ put_request("/v1/b2b/sso/saml/#{organization_id}/connections/#{connection_id}/url", request, headers)
426
572
  end
427
573
 
428
574
  # Delete a SAML verification certificate.
429
575
  #
430
576
  # You may need to do this when rotating certificates from your IdP, since Stytch allows a maximum of 5 certificates per connection. There must always be at least one certificate per active connection.
577
+ # /%}
431
578
  #
432
579
  # == Parameters:
433
580
  # organization_id::
@@ -451,12 +598,18 @@ module StytchB2B
451
598
  # status_code::
452
599
  # 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.
453
600
  # The type of this field is +Integer+.
601
+ #
602
+ # == Method Options:
603
+ # This method supports an optional +DeleteVerificationCertificateRequestOptions+ object which will modify the headers sent in the HTTP request.
454
604
  def delete_verification_certificate(
455
605
  organization_id:,
456
606
  connection_id:,
457
- certificate_id:
607
+ certificate_id:,
608
+ method_options: nil
458
609
  )
459
- delete_request("/v1/b2b/sso/saml/#{organization_id}/connections/#{connection_id}/verification_certificates/#{certificate_id}")
610
+ headers = {}
611
+ headers = headers.merge(method_options.to_headers) unless method_options.nil?
612
+ delete_request("/v1/b2b/sso/saml/#{organization_id}/connections/#{connection_id}/verification_certificates/#{certificate_id}", headers)
460
613
  end
461
614
  end
462
615
  end