workos 5.26.1__tar.gz → 5.28.0__tar.gz

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.
Files changed (156) hide show
  1. {workos-5.26.1 → workos-5.28.0}/PKG-INFO +1 -1
  2. {workos-5.26.1 → workos-5.28.0}/tests/test_session.py +80 -6
  3. {workos-5.26.1 → workos-5.28.0}/workos/__about__.py +1 -1
  4. {workos-5.26.1 → workos-5.28.0}/workos/session.py +3 -0
  5. {workos-5.26.1 → workos-5.28.0}/workos/types/events/event.py +10 -0
  6. {workos-5.26.1 → workos-5.28.0}/workos/types/events/event_type.py +2 -0
  7. {workos-5.26.1 → workos-5.28.0}/workos/types/user_management/organization_membership.py +2 -1
  8. {workos-5.26.1 → workos-5.28.0}/workos/types/user_management/session.py +4 -1
  9. {workos-5.26.1 → workos-5.28.0}/workos/types/webhooks/webhook.py +30 -3
  10. {workos-5.26.1 → workos-5.28.0}/workos/user_management.py +51 -12
  11. {workos-5.26.1 → workos-5.28.0}/workos.egg-info/PKG-INFO +1 -1
  12. {workos-5.26.1 → workos-5.28.0}/LICENSE +0 -0
  13. {workos-5.26.1 → workos-5.28.0}/README.md +0 -0
  14. {workos-5.26.1 → workos-5.28.0}/setup.cfg +0 -0
  15. {workos-5.26.1 → workos-5.28.0}/setup.py +0 -0
  16. {workos-5.26.1 → workos-5.28.0}/tests/test_async_http_client.py +0 -0
  17. {workos-5.26.1 → workos-5.28.0}/tests/test_audit_logs.py +0 -0
  18. {workos-5.26.1 → workos-5.28.0}/tests/test_client.py +0 -0
  19. {workos-5.26.1 → workos-5.28.0}/tests/test_directory_sync.py +0 -0
  20. {workos-5.26.1 → workos-5.28.0}/tests/test_events.py +0 -0
  21. {workos-5.26.1 → workos-5.28.0}/tests/test_fga.py +0 -0
  22. {workos-5.26.1 → workos-5.28.0}/tests/test_mfa.py +0 -0
  23. {workos-5.26.1 → workos-5.28.0}/tests/test_organization_domains.py +0 -0
  24. {workos-5.26.1 → workos-5.28.0}/tests/test_organizations.py +0 -0
  25. {workos-5.26.1 → workos-5.28.0}/tests/test_passwordless.py +0 -0
  26. {workos-5.26.1 → workos-5.28.0}/tests/test_portal.py +0 -0
  27. {workos-5.26.1 → workos-5.28.0}/tests/test_sso.py +0 -0
  28. {workos-5.26.1 → workos-5.28.0}/tests/test_sync_http_client.py +0 -0
  29. {workos-5.26.1 → workos-5.28.0}/tests/test_user_management.py +0 -0
  30. {workos-5.26.1 → workos-5.28.0}/tests/test_vault.py +0 -0
  31. {workos-5.26.1 → workos-5.28.0}/tests/test_webhooks.py +0 -0
  32. {workos-5.26.1 → workos-5.28.0}/tests/test_widgets.py +0 -0
  33. {workos-5.26.1 → workos-5.28.0}/workos/__init__.py +0 -0
  34. {workos-5.26.1 → workos-5.28.0}/workos/_base_client.py +0 -0
  35. {workos-5.26.1 → workos-5.28.0}/workos/_client_configuration.py +0 -0
  36. {workos-5.26.1 → workos-5.28.0}/workos/async_client.py +0 -0
  37. {workos-5.26.1 → workos-5.28.0}/workos/audit_logs.py +0 -0
  38. {workos-5.26.1 → workos-5.28.0}/workos/client.py +0 -0
  39. {workos-5.26.1 → workos-5.28.0}/workos/directory_sync.py +0 -0
  40. {workos-5.26.1 → workos-5.28.0}/workos/events.py +0 -0
  41. {workos-5.26.1 → workos-5.28.0}/workos/exceptions.py +0 -0
  42. {workos-5.26.1 → workos-5.28.0}/workos/fga.py +0 -0
  43. {workos-5.26.1 → workos-5.28.0}/workos/mfa.py +0 -0
  44. {workos-5.26.1 → workos-5.28.0}/workos/organization_domains.py +0 -0
  45. {workos-5.26.1 → workos-5.28.0}/workos/organizations.py +0 -0
  46. {workos-5.26.1 → workos-5.28.0}/workos/passwordless.py +0 -0
  47. {workos-5.26.1 → workos-5.28.0}/workos/portal.py +0 -0
  48. {workos-5.26.1 → workos-5.28.0}/workos/py.typed +0 -0
  49. {workos-5.26.1 → workos-5.28.0}/workos/sso.py +0 -0
  50. {workos-5.26.1 → workos-5.28.0}/workos/types/__init__.py +0 -0
  51. {workos-5.26.1 → workos-5.28.0}/workos/types/audit_logs/__init__.py +0 -0
  52. {workos-5.26.1 → workos-5.28.0}/workos/types/audit_logs/audit_log_event.py +0 -0
  53. {workos-5.26.1 → workos-5.28.0}/workos/types/audit_logs/audit_log_event_actor.py +0 -0
  54. {workos-5.26.1 → workos-5.28.0}/workos/types/audit_logs/audit_log_event_context.py +0 -0
  55. {workos-5.26.1 → workos-5.28.0}/workos/types/audit_logs/audit_log_event_target.py +0 -0
  56. {workos-5.26.1 → workos-5.28.0}/workos/types/audit_logs/audit_log_export.py +0 -0
  57. {workos-5.26.1 → workos-5.28.0}/workos/types/audit_logs/audit_log_metadata.py +0 -0
  58. {workos-5.26.1 → workos-5.28.0}/workos/types/directory_sync/__init__.py +0 -0
  59. {workos-5.26.1 → workos-5.28.0}/workos/types/directory_sync/directory.py +0 -0
  60. {workos-5.26.1 → workos-5.28.0}/workos/types/directory_sync/directory_group.py +0 -0
  61. {workos-5.26.1 → workos-5.28.0}/workos/types/directory_sync/directory_state.py +0 -0
  62. {workos-5.26.1 → workos-5.28.0}/workos/types/directory_sync/directory_type.py +0 -0
  63. {workos-5.26.1 → workos-5.28.0}/workos/types/directory_sync/directory_user.py +0 -0
  64. {workos-5.26.1 → workos-5.28.0}/workos/types/directory_sync/list_filters.py +0 -0
  65. {workos-5.26.1 → workos-5.28.0}/workos/types/events/__init__.py +0 -0
  66. {workos-5.26.1 → workos-5.28.0}/workos/types/events/authentication_payload.py +0 -0
  67. {workos-5.26.1 → workos-5.28.0}/workos/types/events/connection_payload_with_legacy_fields.py +0 -0
  68. {workos-5.26.1 → workos-5.28.0}/workos/types/events/directory_group_membership_payload.py +0 -0
  69. {workos-5.26.1 → workos-5.28.0}/workos/types/events/directory_group_with_previous_attributes.py +0 -0
  70. {workos-5.26.1 → workos-5.28.0}/workos/types/events/directory_payload.py +0 -0
  71. {workos-5.26.1 → workos-5.28.0}/workos/types/events/directory_payload_with_legacy_fields.py +0 -0
  72. {workos-5.26.1 → workos-5.28.0}/workos/types/events/directory_user_with_previous_attributes.py +0 -0
  73. {workos-5.26.1 → workos-5.28.0}/workos/types/events/event_model.py +0 -0
  74. {workos-5.26.1 → workos-5.28.0}/workos/types/events/list_filters.py +0 -0
  75. {workos-5.26.1 → workos-5.28.0}/workos/types/events/organization_domain_verification_failed_payload.py +0 -0
  76. {workos-5.26.1 → workos-5.28.0}/workos/types/events/previous_attributes.py +0 -0
  77. {workos-5.26.1 → workos-5.28.0}/workos/types/events/session_created_payload.py +0 -0
  78. {workos-5.26.1 → workos-5.28.0}/workos/types/fga/__init__.py +0 -0
  79. {workos-5.26.1 → workos-5.28.0}/workos/types/fga/authorization_resource_types.py +0 -0
  80. {workos-5.26.1 → workos-5.28.0}/workos/types/fga/authorization_resources.py +0 -0
  81. {workos-5.26.1 → workos-5.28.0}/workos/types/fga/check.py +0 -0
  82. {workos-5.26.1 → workos-5.28.0}/workos/types/fga/list_filters.py +0 -0
  83. {workos-5.26.1 → workos-5.28.0}/workos/types/fga/warnings.py +0 -0
  84. {workos-5.26.1 → workos-5.28.0}/workos/types/fga/warrant.py +0 -0
  85. {workos-5.26.1 → workos-5.28.0}/workos/types/list_resource.py +0 -0
  86. {workos-5.26.1 → workos-5.28.0}/workos/types/metadata.py +0 -0
  87. {workos-5.26.1 → workos-5.28.0}/workos/types/mfa/__init__.py +0 -0
  88. {workos-5.26.1 → workos-5.28.0}/workos/types/mfa/authentication_challenge.py +0 -0
  89. {workos-5.26.1 → workos-5.28.0}/workos/types/mfa/authentication_challenge_verification_response.py +0 -0
  90. {workos-5.26.1 → workos-5.28.0}/workos/types/mfa/authentication_factor.py +0 -0
  91. {workos-5.26.1 → workos-5.28.0}/workos/types/mfa/authentication_factor_totp_and_challenge_response.py +0 -0
  92. {workos-5.26.1 → workos-5.28.0}/workos/types/mfa/enroll_authentication_factor_type.py +0 -0
  93. {workos-5.26.1 → workos-5.28.0}/workos/types/organization_domains/__init__.py +0 -0
  94. {workos-5.26.1 → workos-5.28.0}/workos/types/organization_domains/organization_domain.py +0 -0
  95. {workos-5.26.1 → workos-5.28.0}/workos/types/organizations/__init__.py +0 -0
  96. {workos-5.26.1 → workos-5.28.0}/workos/types/organizations/domain_data_input.py +0 -0
  97. {workos-5.26.1 → workos-5.28.0}/workos/types/organizations/list_filters.py +0 -0
  98. {workos-5.26.1 → workos-5.28.0}/workos/types/organizations/organization.py +0 -0
  99. {workos-5.26.1 → workos-5.28.0}/workos/types/organizations/organization_common.py +0 -0
  100. {workos-5.26.1 → workos-5.28.0}/workos/types/passwordless/__init__.py +0 -0
  101. {workos-5.26.1 → workos-5.28.0}/workos/types/passwordless/passwordless_session.py +0 -0
  102. {workos-5.26.1 → workos-5.28.0}/workos/types/passwordless/passwordless_session_type.py +0 -0
  103. {workos-5.26.1 → workos-5.28.0}/workos/types/portal/__init__.py +0 -0
  104. {workos-5.26.1 → workos-5.28.0}/workos/types/portal/portal_link.py +0 -0
  105. {workos-5.26.1 → workos-5.28.0}/workos/types/portal/portal_link_intent.py +0 -0
  106. {workos-5.26.1 → workos-5.28.0}/workos/types/portal/portal_link_intent_options.py +0 -0
  107. {workos-5.26.1 → workos-5.28.0}/workos/types/roles/__init__.py +0 -0
  108. {workos-5.26.1 → workos-5.28.0}/workos/types/roles/role.py +0 -0
  109. {workos-5.26.1 → workos-5.28.0}/workos/types/sso/__init__.py +0 -0
  110. {workos-5.26.1 → workos-5.28.0}/workos/types/sso/connection.py +0 -0
  111. {workos-5.26.1 → workos-5.28.0}/workos/types/sso/connection_domain.py +0 -0
  112. {workos-5.26.1 → workos-5.28.0}/workos/types/sso/profile.py +0 -0
  113. {workos-5.26.1 → workos-5.28.0}/workos/types/sso/sso_provider_type.py +0 -0
  114. {workos-5.26.1 → workos-5.28.0}/workos/types/user_management/__init__.py +0 -0
  115. {workos-5.26.1 → workos-5.28.0}/workos/types/user_management/authenticate_with_common.py +0 -0
  116. {workos-5.26.1 → workos-5.28.0}/workos/types/user_management/authentication_response.py +0 -0
  117. {workos-5.26.1 → workos-5.28.0}/workos/types/user_management/email_verification.py +0 -0
  118. {workos-5.26.1 → workos-5.28.0}/workos/types/user_management/impersonator.py +0 -0
  119. {workos-5.26.1 → workos-5.28.0}/workos/types/user_management/invitation.py +0 -0
  120. {workos-5.26.1 → workos-5.28.0}/workos/types/user_management/list_filters.py +0 -0
  121. {workos-5.26.1 → workos-5.28.0}/workos/types/user_management/magic_auth.py +0 -0
  122. {workos-5.26.1 → workos-5.28.0}/workos/types/user_management/oauth_tokens.py +0 -0
  123. {workos-5.26.1 → workos-5.28.0}/workos/types/user_management/password_hash_type.py +0 -0
  124. {workos-5.26.1 → workos-5.28.0}/workos/types/user_management/password_reset.py +0 -0
  125. {workos-5.26.1 → workos-5.28.0}/workos/types/user_management/screen_hint.py +0 -0
  126. {workos-5.26.1 → workos-5.28.0}/workos/types/user_management/user.py +0 -0
  127. {workos-5.26.1 → workos-5.28.0}/workos/types/user_management/user_management_provider_type.py +0 -0
  128. {workos-5.26.1 → workos-5.28.0}/workos/types/vault/__init__.py +0 -0
  129. {workos-5.26.1 → workos-5.28.0}/workos/types/vault/key.py +0 -0
  130. {workos-5.26.1 → workos-5.28.0}/workos/types/vault/object.py +0 -0
  131. {workos-5.26.1 → workos-5.28.0}/workos/types/webhooks/__init__.py +0 -0
  132. {workos-5.26.1 → workos-5.28.0}/workos/types/webhooks/webhook_model.py +0 -0
  133. {workos-5.26.1 → workos-5.28.0}/workos/types/webhooks/webhook_payload.py +0 -0
  134. {workos-5.26.1 → workos-5.28.0}/workos/types/widgets/__init__.py +0 -0
  135. {workos-5.26.1 → workos-5.28.0}/workos/types/widgets/widget_scope.py +0 -0
  136. {workos-5.26.1 → workos-5.28.0}/workos/types/widgets/widget_token_response.py +0 -0
  137. {workos-5.26.1 → workos-5.28.0}/workos/types/workos_model.py +0 -0
  138. {workos-5.26.1 → workos-5.28.0}/workos/typing/__init__.py +0 -0
  139. {workos-5.26.1 → workos-5.28.0}/workos/typing/literals.py +0 -0
  140. {workos-5.26.1 → workos-5.28.0}/workos/typing/sync_or_async.py +0 -0
  141. {workos-5.26.1 → workos-5.28.0}/workos/typing/untyped_literal.py +0 -0
  142. {workos-5.26.1 → workos-5.28.0}/workos/typing/webhooks.py +0 -0
  143. {workos-5.26.1 → workos-5.28.0}/workos/utils/__init__.py +0 -0
  144. {workos-5.26.1 → workos-5.28.0}/workos/utils/_base_http_client.py +0 -0
  145. {workos-5.26.1 → workos-5.28.0}/workos/utils/crypto_provider.py +0 -0
  146. {workos-5.26.1 → workos-5.28.0}/workos/utils/http_client.py +0 -0
  147. {workos-5.26.1 → workos-5.28.0}/workos/utils/pagination_order.py +0 -0
  148. {workos-5.26.1 → workos-5.28.0}/workos/utils/request_helper.py +0 -0
  149. {workos-5.26.1 → workos-5.28.0}/workos/vault.py +0 -0
  150. {workos-5.26.1 → workos-5.28.0}/workos/webhooks.py +0 -0
  151. {workos-5.26.1 → workos-5.28.0}/workos/widgets.py +0 -0
  152. {workos-5.26.1 → workos-5.28.0}/workos.egg-info/SOURCES.txt +0 -0
  153. {workos-5.26.1 → workos-5.28.0}/workos.egg-info/dependency_links.txt +0 -0
  154. {workos-5.26.1 → workos-5.28.0}/workos.egg-info/not-zip-safe +0 -0
  155. {workos-5.26.1 → workos-5.28.0}/workos.egg-info/requires.txt +0 -0
  156. {workos-5.26.1 → workos-5.28.0}/workos.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: workos
3
- Version: 5.26.1
3
+ Version: 5.28.0
4
4
  Summary: WorkOS Python Client
5
5
  Home-page: https://github.com/workos-inc/workos-python
6
6
  Author: WorkOS
@@ -1,8 +1,11 @@
1
- import pytest
1
+ import concurrent.futures
2
+ from datetime import datetime, timezone
2
3
  from unittest.mock import AsyncMock, Mock, patch
4
+
3
5
  import jwt
4
- from datetime import datetime, timezone
5
- import concurrent.futures
6
+ import pytest
7
+ from cryptography.hazmat.primitives import serialization
8
+ from cryptography.hazmat.primitives.asymmetric import rsa
6
9
 
7
10
  from tests.conftest import with_jwks_mock
8
11
  from workos.session import AsyncSession, Session, _get_jwks_client
@@ -16,9 +19,6 @@ from workos.types.user_management.session import (
16
19
  RefreshWithSessionCookieSuccessResponse,
17
20
  )
18
21
 
19
- from cryptography.hazmat.primitives import serialization
20
- from cryptography.hazmat.primitives.asymmetric import rsa
21
-
22
22
 
23
23
  class SessionFixtures:
24
24
  @pytest.fixture(autouse=True)
@@ -48,6 +48,7 @@ class SessionFixtures:
48
48
  "sid": "session_123",
49
49
  "org_id": "organization_123",
50
50
  "role": "admin",
51
+ "roles": ["admin"],
51
52
  "permissions": ["read"],
52
53
  "entitlements": ["feature_1"],
53
54
  "exp": int(current_datetime.timestamp()) + 3600,
@@ -215,6 +216,7 @@ class TestSessionBase(SessionFixtures):
215
216
  "sid": session_constants["SESSION_ID"],
216
217
  "org_id": session_constants["ORGANIZATION_ID"],
217
218
  "role": "admin",
219
+ "roles": ["admin"],
218
220
  "permissions": ["read"],
219
221
  "entitlements": ["feature_1"],
220
222
  "exp": int(datetime.now(timezone.utc).timestamp()) + 3600,
@@ -239,6 +241,7 @@ class TestSessionBase(SessionFixtures):
239
241
  "sid": session_constants["SESSION_ID"],
240
242
  "org_id": session_constants["ORGANIZATION_ID"],
241
243
  "role": "admin",
244
+ "roles": ["admin"],
242
245
  "permissions": ["read"],
243
246
  "entitlements": ["feature_1"],
244
247
  }
@@ -257,11 +260,80 @@ class TestSessionBase(SessionFixtures):
257
260
  assert response.session_id == session_constants["SESSION_ID"]
258
261
  assert response.organization_id == session_constants["ORGANIZATION_ID"]
259
262
  assert response.role == "admin"
263
+ assert response.roles == ["admin"]
260
264
  assert response.permissions == ["read"]
261
265
  assert response.entitlements == ["feature_1"]
262
266
  assert response.user.id == session_constants["USER_ID"]
263
267
  assert response.impersonator is None
264
268
 
269
+ @with_jwks_mock
270
+ def test_authenticate_success_with_roles(
271
+ self, session_constants, mock_user_management
272
+ ):
273
+ session = Session(
274
+ user_management=mock_user_management,
275
+ client_id=session_constants["CLIENT_ID"],
276
+ session_data=session_constants["SESSION_DATA"],
277
+ cookie_password=session_constants["COOKIE_PASSWORD"],
278
+ )
279
+
280
+ # Mock the session data that would be unsealed
281
+ mock_session = {
282
+ "access_token": jwt.encode(
283
+ {
284
+ "sid": session_constants["SESSION_ID"],
285
+ "org_id": session_constants["ORGANIZATION_ID"],
286
+ "role": "admin",
287
+ "roles": ["admin", "member"],
288
+ "permissions": ["read", "write"],
289
+ "entitlements": ["feature_1"],
290
+ "exp": int(datetime.now(timezone.utc).timestamp()) + 3600,
291
+ "iat": int(datetime.now(timezone.utc).timestamp()),
292
+ },
293
+ session_constants["PRIVATE_KEY"],
294
+ algorithm="RS256",
295
+ ),
296
+ "user": {
297
+ "object": "user",
298
+ "id": session_constants["USER_ID"],
299
+ "email": "user@example.com",
300
+ "email_verified": True,
301
+ "created_at": session_constants["CURRENT_TIMESTAMP"],
302
+ "updated_at": session_constants["CURRENT_TIMESTAMP"],
303
+ },
304
+ "impersonator": None,
305
+ }
306
+
307
+ # Mock the JWT payload that would be decoded
308
+ mock_jwt_payload = {
309
+ "sid": session_constants["SESSION_ID"],
310
+ "org_id": session_constants["ORGANIZATION_ID"],
311
+ "role": "admin",
312
+ "roles": ["admin", "member"],
313
+ "permissions": ["read", "write"],
314
+ "entitlements": ["feature_1"],
315
+ }
316
+
317
+ with patch.object(Session, "unseal_data", return_value=mock_session), patch(
318
+ "jwt.decode", return_value=mock_jwt_payload
319
+ ), patch.object(
320
+ session.jwks,
321
+ "get_signing_key_from_jwt",
322
+ return_value=Mock(key=session_constants["PUBLIC_KEY"]),
323
+ ):
324
+ response = session.authenticate()
325
+
326
+ assert isinstance(response, AuthenticateWithSessionCookieSuccessResponse)
327
+ assert response.authenticated is True
328
+ assert response.session_id == session_constants["SESSION_ID"]
329
+ assert response.organization_id == session_constants["ORGANIZATION_ID"]
330
+ assert response.role == "admin"
331
+ assert response.roles == ["admin", "member"]
332
+ assert response.permissions == ["read", "write"]
333
+ assert response.entitlements == ["feature_1"]
334
+ assert response.user.id == session_constants["USER_ID"]
335
+ assert response.impersonator is None
336
+
265
337
  @with_jwks_mock
266
338
  def test_refresh_invalid_session_cookie(
267
339
  self, session_constants, mock_user_management
@@ -335,6 +407,7 @@ class TestSession(SessionFixtures):
335
407
  "sid": session_constants["SESSION_ID"],
336
408
  "org_id": session_constants["ORGANIZATION_ID"],
337
409
  "role": "admin",
410
+ "roles": ["admin"],
338
411
  "permissions": ["read"],
339
412
  "entitlements": ["feature_1"],
340
413
  },
@@ -435,6 +508,7 @@ class TestAsyncSession(SessionFixtures):
435
508
  "sid": session_constants["SESSION_ID"],
436
509
  "org_id": session_constants["ORGANIZATION_ID"],
437
510
  "role": "admin",
511
+ "roles": ["admin"],
438
512
  "permissions": ["read"],
439
513
  "entitlements": ["feature_1"],
440
514
  },
@@ -12,7 +12,7 @@ __package_name__ = "workos"
12
12
 
13
13
  __package_url__ = "https://github.com/workos-inc/workos-python"
14
14
 
15
- __version__ = "5.26.1"
15
+ __version__ = "5.28.0"
16
16
 
17
17
  __author__ = "WorkOS"
18
18
 
@@ -102,6 +102,7 @@ class SessionModule(Protocol):
102
102
  session_id=decoded["sid"],
103
103
  organization_id=decoded.get("org_id", None),
104
104
  role=decoded.get("role", None),
105
+ roles=decoded.get("roles", None),
105
106
  permissions=decoded.get("permissions", None),
106
107
  entitlements=decoded.get("entitlements", None),
107
108
  user=session["user"],
@@ -229,6 +230,7 @@ class Session(SessionModule):
229
230
  session_id=decoded["sid"],
230
231
  organization_id=decoded.get("org_id", None),
231
232
  role=decoded.get("role", None),
233
+ roles=decoded.get("roles", None),
232
234
  permissions=decoded.get("permissions", None),
233
235
  entitlements=decoded.get("entitlements", None),
234
236
  user=auth_response.user,
@@ -319,6 +321,7 @@ class AsyncSession(SessionModule):
319
321
  session_id=decoded["sid"],
320
322
  organization_id=decoded.get("org_id", None),
321
323
  role=decoded.get("role", None),
324
+ roles=decoded.get("roles", None),
322
325
  permissions=decoded.get("permissions", None),
323
326
  entitlements=decoded.get("entitlements", None),
324
327
  user=auth_response.user,
@@ -163,10 +163,18 @@ class EmailVerificationCreatedEvent(EventModel[EmailVerificationCommon]):
163
163
  event: Literal["email_verification.created"]
164
164
 
165
165
 
166
+ class InvitationAcceptedEvent(EventModel[InvitationCommon]):
167
+ event: Literal["invitation.accepted"]
168
+
169
+
166
170
  class InvitationCreatedEvent(EventModel[InvitationCommon]):
167
171
  event: Literal["invitation.created"]
168
172
 
169
173
 
174
+ class InvitationRevokedEvent(EventModel[InvitationCommon]):
175
+ event: Literal["invitation.revoked"]
176
+
177
+
170
178
  class MagicAuthCreatedEvent(EventModel[MagicAuthCommon]):
171
179
  event: Literal["magic_auth.created"]
172
180
 
@@ -279,7 +287,9 @@ Event = Annotated[
279
287
  DirectoryUserAddedToGroupEvent,
280
288
  DirectoryUserRemovedFromGroupEvent,
281
289
  EmailVerificationCreatedEvent,
290
+ InvitationAcceptedEvent,
282
291
  InvitationCreatedEvent,
292
+ InvitationRevokedEvent,
283
293
  MagicAuthCreatedEvent,
284
294
  OrganizationCreatedEvent,
285
295
  OrganizationDeletedEvent,
@@ -29,7 +29,9 @@ EventType = Literal[
29
29
  "dsync.group.user_added",
30
30
  "dsync.group.user_removed",
31
31
  "email_verification.created",
32
+ "invitation.accepted",
32
33
  "invitation.created",
34
+ "invitation.revoked",
33
35
  "magic_auth.created",
34
36
  "organization.created",
35
37
  "organization.deleted",
@@ -1,4 +1,4 @@
1
- from typing import Literal
1
+ from typing import Literal, Sequence, Optional
2
2
  from typing_extensions import TypedDict
3
3
 
4
4
  from workos.types.workos_model import WorkOSModel
@@ -19,6 +19,7 @@ class OrganizationMembership(WorkOSModel):
19
19
  user_id: str
20
20
  organization_id: str
21
21
  role: OrganizationMembershipRole
22
+ roles: Optional[Sequence[OrganizationMembershipRole]] = None
22
23
  status: LiteralOrUntyped[OrganizationMembershipStatus]
23
24
  created_at: str
24
25
  updated_at: str
@@ -1,6 +1,8 @@
1
- from typing import Optional, Sequence, TypedDict, Union
2
1
  from enum import Enum
2
+ from typing import Optional, Sequence, TypedDict, Union
3
+
3
4
  from typing_extensions import Literal
5
+
4
6
  from workos.types.user_management.impersonator import Impersonator
5
7
  from workos.types.user_management.user import User
6
8
  from workos.types.workos_model import WorkOSModel
@@ -17,6 +19,7 @@ class AuthenticateWithSessionCookieSuccessResponse(WorkOSModel):
17
19
  session_id: str
18
20
  organization_id: Optional[str] = None
19
21
  role: Optional[str] = None
22
+ roles: Optional[Sequence[str]] = None
20
23
  permissions: Optional[Sequence[str]] = None
21
24
  user: User
22
25
  impersonator: Optional[Impersonator] = None
@@ -1,9 +1,9 @@
1
1
  from typing import Literal, Union
2
+
2
3
  from pydantic import Field
3
4
  from typing_extensions import Annotated
5
+
4
6
  from workos.types.directory_sync import DirectoryGroup
5
- from workos.types.user_management import OrganizationMembership, User
6
- from workos.types.webhooks.webhook_model import WebhookModel
7
7
  from workos.types.directory_sync.directory_user import DirectoryUser
8
8
  from workos.types.events.authentication_payload import (
9
9
  AuthenticationEmailVerificationSucceededPayload,
@@ -37,16 +37,18 @@ from workos.types.events.organization_domain_verification_failed_payload import
37
37
  OrganizationDomainVerificationFailedPayload,
38
38
  )
39
39
  from workos.types.events.session_created_payload import SessionCreatedPayload
40
- from workos.types.organizations.organization_common import OrganizationCommon
41
40
  from workos.types.organization_domains import OrganizationDomain
41
+ from workos.types.organizations.organization_common import OrganizationCommon
42
42
  from workos.types.roles.role import EventRole
43
43
  from workos.types.sso.connection import Connection
44
+ from workos.types.user_management import OrganizationMembership, User
44
45
  from workos.types.user_management.email_verification import (
45
46
  EmailVerificationCommon,
46
47
  )
47
48
  from workos.types.user_management.invitation import InvitationCommon
48
49
  from workos.types.user_management.magic_auth import MagicAuthCommon
49
50
  from workos.types.user_management.password_reset import PasswordResetCommon
51
+ from workos.types.webhooks.webhook_model import WebhookModel
50
52
 
51
53
  # README
52
54
  # When adding a new webhook event type, ensure the new webhook class is
@@ -167,10 +169,18 @@ class EmailVerificationCreatedWebhook(WebhookModel[EmailVerificationCommon]):
167
169
  event: Literal["email_verification.created"]
168
170
 
169
171
 
172
+ class InvitationAcceptedWebhook(WebhookModel[InvitationCommon]):
173
+ event: Literal["invitation.accepted"]
174
+
175
+
170
176
  class InvitationCreatedWebhook(WebhookModel[InvitationCommon]):
171
177
  event: Literal["invitation.created"]
172
178
 
173
179
 
180
+ class InvitationRevokedWebhook(WebhookModel[InvitationCommon]):
181
+ event: Literal["invitation.revoked"]
182
+
183
+
174
184
  class MagicAuthCreatedWebhook(WebhookModel[MagicAuthCommon]):
175
185
  event: Literal["magic_auth.created"]
176
186
 
@@ -197,6 +207,18 @@ class OrganizationDomainVerifiedWebhook(WebhookModel[OrganizationDomain]):
197
207
  event: Literal["organization_domain.verified"]
198
208
 
199
209
 
210
+ class OrganizationDomainCreatedWebhook(WebhookModel[OrganizationDomain]):
211
+ event: Literal["organization_domain.created"]
212
+
213
+
214
+ class OrganizationDomainUpdatedWebhook(WebhookModel[OrganizationDomain]):
215
+ event: Literal["organization_domain.updated"]
216
+
217
+
218
+ class OrganizationDomainDeletedWebhook(WebhookModel[OrganizationDomain]):
219
+ event: Literal["organization_domain.deleted"]
220
+
221
+
200
222
  class OrganizationMembershipCreatedWebhook(WebhookModel[OrganizationMembership]):
201
223
  event: Literal["organization_membership.created"]
202
224
 
@@ -271,11 +293,16 @@ Webhook = Annotated[
271
293
  DirectoryUserAddedToGroupWebhook,
272
294
  DirectoryUserRemovedFromGroupWebhook,
273
295
  EmailVerificationCreatedWebhook,
296
+ InvitationAcceptedWebhook,
274
297
  InvitationCreatedWebhook,
298
+ InvitationRevokedWebhook,
275
299
  MagicAuthCreatedWebhook,
276
300
  OrganizationCreatedWebhook,
277
301
  OrganizationDeletedWebhook,
278
302
  OrganizationUpdatedWebhook,
303
+ OrganizationDomainCreatedWebhook,
304
+ OrganizationDomainDeletedWebhook,
305
+ OrganizationDomainUpdatedWebhook,
279
306
  OrganizationDomainVerificationFailedWebhook,
280
307
  OrganizationDomainVerifiedWebhook,
281
308
  OrganizationMembershipCreatedWebhook,
@@ -245,15 +245,24 @@ class UserManagementModule(Protocol):
245
245
  ...
246
246
 
247
247
  def create_organization_membership(
248
- self, *, user_id: str, organization_id: str, role_slug: Optional[str] = None
248
+ self,
249
+ *,
250
+ user_id: str,
251
+ organization_id: str,
252
+ role_slug: Optional[str] = None,
253
+ role_slugs: Optional[Sequence[str]] = None,
249
254
  ) -> SyncOrAsync[OrganizationMembership]:
250
255
  """Create a new OrganizationMembership for the given Organization and User.
251
256
 
252
257
  Kwargs:
253
- user_id: The Unique ID of the User.
254
- organization_id: The Unique ID of the Organization to which the user belongs to.
255
- role_slug: The Unique Slug of the Role to which to grant to this membership.
256
- If no slug is passed in, the default role will be granted.(Optional)
258
+ user_id: The unique ID of the User.
259
+ organization_id: The unique ID of the Organization to which the user belongs to.
260
+ role_slug: The unique slug of the role to grant to this membership.(Optional)
261
+ role_slugs: The unique slugs of the roles to grant to this membership.(Optional)
262
+
263
+ Note:
264
+ role_slug and role_slugs are mutually exclusive. If neither is provided,
265
+ the user will be assigned the organization's default role.
257
266
 
258
267
  Returns:
259
268
  OrganizationMembership: Created OrganizationMembership response from WorkOS.
@@ -261,14 +270,22 @@ class UserManagementModule(Protocol):
261
270
  ...
262
271
 
263
272
  def update_organization_membership(
264
- self, *, organization_membership_id: str, role_slug: Optional[str] = None
273
+ self,
274
+ *,
275
+ organization_membership_id: str,
276
+ role_slug: Optional[str] = None,
277
+ role_slugs: Optional[Sequence[str]] = None,
265
278
  ) -> SyncOrAsync[OrganizationMembership]:
266
279
  """Updates an OrganizationMembership for the given id.
267
280
 
268
281
  Args:
269
282
  organization_membership_id (str): The unique ID of the Organization Membership.
270
- role_slug: The Unique Slug of the Role to which to grant to this membership.
271
- If no slug is passed in, it will not be changed (Optional)
283
+ role_slug: The unique slug of the role to grant to this membership.(Optional)
284
+ role_slugs: The unique slugs of the roles to grant to this membership.(Optional)
285
+
286
+ Note:
287
+ role_slug and role_slugs are mutually exclusive. If neither is provided,
288
+ the role(s) of the membership will remain unchanged.
272
289
 
273
290
  Returns:
274
291
  OrganizationMembership: Updated OrganizationMembership response from WorkOS.
@@ -988,12 +1005,18 @@ class UserManagement(UserManagementModule):
988
1005
  )
989
1006
 
990
1007
  def create_organization_membership(
991
- self, *, user_id: str, organization_id: str, role_slug: Optional[str] = None
1008
+ self,
1009
+ *,
1010
+ user_id: str,
1011
+ organization_id: str,
1012
+ role_slug: Optional[str] = None,
1013
+ role_slugs: Optional[Sequence[str]] = None,
992
1014
  ) -> OrganizationMembership:
993
1015
  json = {
994
1016
  "user_id": user_id,
995
1017
  "organization_id": organization_id,
996
1018
  "role_slug": role_slug,
1019
+ "role_slugs": role_slugs,
997
1020
  }
998
1021
 
999
1022
  response = self._http_client.request(
@@ -1003,10 +1026,15 @@ class UserManagement(UserManagementModule):
1003
1026
  return OrganizationMembership.model_validate(response)
1004
1027
 
1005
1028
  def update_organization_membership(
1006
- self, *, organization_membership_id: str, role_slug: Optional[str] = None
1029
+ self,
1030
+ *,
1031
+ organization_membership_id: str,
1032
+ role_slug: Optional[str] = None,
1033
+ role_slugs: Optional[Sequence[str]] = None,
1007
1034
  ) -> OrganizationMembership:
1008
1035
  json = {
1009
1036
  "role_slug": role_slug,
1037
+ "role_slugs": role_slugs,
1010
1038
  }
1011
1039
 
1012
1040
  response = self._http_client.request(
@@ -1614,12 +1642,18 @@ class AsyncUserManagement(UserManagementModule):
1614
1642
  )
1615
1643
 
1616
1644
  async def create_organization_membership(
1617
- self, *, user_id: str, organization_id: str, role_slug: Optional[str] = None
1645
+ self,
1646
+ *,
1647
+ user_id: str,
1648
+ organization_id: str,
1649
+ role_slug: Optional[str] = None,
1650
+ role_slugs: Optional[Sequence[str]] = None,
1618
1651
  ) -> OrganizationMembership:
1619
1652
  json = {
1620
1653
  "user_id": user_id,
1621
1654
  "organization_id": organization_id,
1622
1655
  "role_slug": role_slug,
1656
+ "role_slugs": role_slugs,
1623
1657
  }
1624
1658
 
1625
1659
  response = await self._http_client.request(
@@ -1629,10 +1663,15 @@ class AsyncUserManagement(UserManagementModule):
1629
1663
  return OrganizationMembership.model_validate(response)
1630
1664
 
1631
1665
  async def update_organization_membership(
1632
- self, *, organization_membership_id: str, role_slug: Optional[str] = None
1666
+ self,
1667
+ *,
1668
+ organization_membership_id: str,
1669
+ role_slug: Optional[str] = None,
1670
+ role_slugs: Optional[Sequence[str]] = None,
1633
1671
  ) -> OrganizationMembership:
1634
1672
  json = {
1635
1673
  "role_slug": role_slug,
1674
+ "role_slugs": role_slugs,
1636
1675
  }
1637
1676
 
1638
1677
  response = await self._http_client.request(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: workos
3
- Version: 5.26.1
3
+ Version: 5.28.0
4
4
  Summary: WorkOS Python Client
5
5
  Home-page: https://github.com/workos-inc/workos-python
6
6
  Author: WorkOS
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes