workos 5.23.0__py3-none-any.whl → 5.26.0__py3-none-any.whl

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.
workos/__about__.py CHANGED
@@ -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.23.0"
15
+ __version__ = "5.26.0"
16
16
 
17
17
  __author__ = "WorkOS"
18
18
 
workos/_base_client.py CHANGED
@@ -11,6 +11,7 @@ from workos.directory_sync import DirectorySyncModule
11
11
  from workos.events import EventsModule
12
12
  from workos.mfa import MFAModule
13
13
  from workos.organizations import OrganizationsModule
14
+ from workos.organization_domains import OrganizationDomainsModule
14
15
  from workos.passwordless import PasswordlessModule
15
16
  from workos.portal import PortalModule
16
17
  from workos.sso import SSOModule
@@ -88,6 +89,10 @@ class BaseClient(ClientConfiguration):
88
89
  @abstractmethod
89
90
  def organizations(self) -> OrganizationsModule: ...
90
91
 
92
+ @property
93
+ @abstractmethod
94
+ def organization_domains(self) -> OrganizationDomainsModule: ...
95
+
91
96
  @property
92
97
  @abstractmethod
93
98
  def passwordless(self) -> PasswordlessModule: ...
workos/async_client.py CHANGED
@@ -7,6 +7,7 @@ from workos.events import AsyncEvents
7
7
  from workos.fga import FGAModule
8
8
  from workos.mfa import MFAModule
9
9
  from workos.organizations import AsyncOrganizations
10
+ from workos.organization_domains import AsyncOrganizationDomains
10
11
  from workos.passwordless import PasswordlessModule
11
12
  from workos.portal import PortalModule
12
13
  from workos.sso import AsyncSSO
@@ -14,6 +15,7 @@ from workos.user_management import AsyncUserManagement
14
15
  from workos.utils.http_client import AsyncHTTPClient
15
16
  from workos.webhooks import WebhooksModule
16
17
  from workos.widgets import WidgetsModule
18
+ from workos.vault import VaultModule
17
19
 
18
20
 
19
21
  class AsyncClient(BaseClient):
@@ -79,6 +81,14 @@ class AsyncClient(BaseClient):
79
81
  self._organizations = AsyncOrganizations(self._http_client)
80
82
  return self._organizations
81
83
 
84
+ @property
85
+ def organization_domains(self) -> AsyncOrganizationDomains:
86
+ if not getattr(self, "_organization_domains", None):
87
+ self._organization_domains = AsyncOrganizationDomains(
88
+ http_client=self._http_client, client_configuration=self
89
+ )
90
+ return self._organization_domains
91
+
82
92
  @property
83
93
  def passwordless(self) -> PasswordlessModule:
84
94
  raise NotImplementedError(
@@ -112,3 +122,9 @@ class AsyncClient(BaseClient):
112
122
  raise NotImplementedError(
113
123
  "Widgets APIs are not yet supported in the async client."
114
124
  )
125
+
126
+ @property
127
+ def vault(self) -> VaultModule:
128
+ raise NotImplementedError(
129
+ "Vault APIs are not yet supported in the async client."
130
+ )
workos/client.py CHANGED
@@ -5,6 +5,7 @@ from workos.audit_logs import AuditLogs
5
5
  from workos.directory_sync import DirectorySync
6
6
  from workos.fga import FGA
7
7
  from workos.organizations import Organizations
8
+ from workos.organization_domains import OrganizationDomains
8
9
  from workos.passwordless import Passwordless
9
10
  from workos.portal import Portal
10
11
  from workos.sso import SSO
@@ -14,6 +15,7 @@ from workos.events import Events
14
15
  from workos.user_management import UserManagement
15
16
  from workos.utils.http_client import SyncHTTPClient
16
17
  from workos.widgets import Widgets
18
+ from workos.vault import Vault
17
19
 
18
20
 
19
21
  class SyncClient(BaseClient):
@@ -79,6 +81,14 @@ class SyncClient(BaseClient):
79
81
  self._organizations = Organizations(self._http_client)
80
82
  return self._organizations
81
83
 
84
+ @property
85
+ def organization_domains(self) -> OrganizationDomains:
86
+ if not getattr(self, "_organization_domains", None):
87
+ self._organization_domains = OrganizationDomains(
88
+ http_client=self._http_client, client_configuration=self
89
+ )
90
+ return self._organization_domains
91
+
82
92
  @property
83
93
  def passwordless(self) -> Passwordless:
84
94
  if not getattr(self, "_passwordless", None):
@@ -116,3 +126,9 @@ class SyncClient(BaseClient):
116
126
  if not getattr(self, "_widgets", None):
117
127
  self._widgets = Widgets(http_client=self._http_client)
118
128
  return self._widgets
129
+
130
+ @property
131
+ def vault(self) -> Vault:
132
+ if not getattr(self, "_vault", None):
133
+ self._vault = Vault(http_client=self._http_client)
134
+ return self._vault
@@ -0,0 +1,179 @@
1
+ from typing import Protocol
2
+ from workos._client_configuration import ClientConfiguration
3
+ from workos.types.organization_domains import OrganizationDomain
4
+ from workos.typing.sync_or_async import SyncOrAsync
5
+ from workos.utils.http_client import AsyncHTTPClient, SyncHTTPClient
6
+ from workos.utils.request_helper import (
7
+ REQUEST_METHOD_DELETE,
8
+ REQUEST_METHOD_GET,
9
+ REQUEST_METHOD_POST,
10
+ )
11
+
12
+
13
+ class OrganizationDomainsModule(Protocol):
14
+ """Offers methods for managing organization domains."""
15
+
16
+ _client_configuration: ClientConfiguration
17
+
18
+ def get_organization_domain(
19
+ self, organization_domain_id: str
20
+ ) -> SyncOrAsync[OrganizationDomain]:
21
+ """Gets a single Organization Domain
22
+
23
+ Args:
24
+ organization_domain_id (str): Organization Domain unique identifier
25
+
26
+ Returns:
27
+ OrganizationDomain: Organization Domain response from WorkOS
28
+ """
29
+ ...
30
+
31
+ def create_organization_domain(
32
+ self,
33
+ organization_id: str,
34
+ domain: str,
35
+ ) -> SyncOrAsync[OrganizationDomain]:
36
+ """Creates an Organization Domain
37
+
38
+ Args:
39
+ organization_id (str): Organization unique identifier
40
+ domain (str): Domain to be added to the organization
41
+
42
+ Returns:
43
+ OrganizationDomain: Organization Domain response from WorkOS
44
+ """
45
+ ...
46
+
47
+ def verify_organization_domain(
48
+ self, organization_domain_id: str
49
+ ) -> SyncOrAsync[OrganizationDomain]:
50
+ """Verifies an Organization Domain
51
+
52
+ Args:
53
+ organization_domain_id (str): Organization Domain unique identifier
54
+
55
+ Returns:
56
+ OrganizationDomain: Organization Domain response from WorkOS
57
+ """
58
+ ...
59
+
60
+ def delete_organization_domain(
61
+ self, organization_domain_id: str
62
+ ) -> SyncOrAsync[None]:
63
+ """Deletes a single Organization Domain
64
+
65
+ Args:
66
+ organization_domain_id (str): Organization Domain unique identifier
67
+
68
+ Returns:
69
+ None
70
+ """
71
+ ...
72
+
73
+
74
+ class OrganizationDomains:
75
+ """Offers methods for managing organization domains."""
76
+
77
+ _http_client: SyncHTTPClient
78
+ _client_configuration: ClientConfiguration
79
+
80
+ def __init__(
81
+ self,
82
+ http_client: SyncHTTPClient,
83
+ client_configuration: ClientConfiguration,
84
+ ):
85
+ self._http_client = http_client
86
+ self._client_configuration = client_configuration
87
+
88
+ def get_organization_domain(
89
+ self, organization_domain_id: str
90
+ ) -> OrganizationDomain:
91
+ response = self._http_client.request(
92
+ f"organization_domains/{organization_domain_id}",
93
+ method=REQUEST_METHOD_GET,
94
+ )
95
+
96
+ return OrganizationDomain.model_validate(response)
97
+
98
+ def create_organization_domain(
99
+ self,
100
+ organization_id: str,
101
+ domain: str,
102
+ ) -> OrganizationDomain:
103
+ response = self._http_client.request(
104
+ "organization_domains",
105
+ method=REQUEST_METHOD_POST,
106
+ json={"organization_id": organization_id, "domain": domain},
107
+ )
108
+
109
+ return OrganizationDomain.model_validate(response)
110
+
111
+ def verify_organization_domain(
112
+ self, organization_domain_id: str
113
+ ) -> OrganizationDomain:
114
+ response = self._http_client.request(
115
+ f"organization_domains/{organization_domain_id}/verify",
116
+ method=REQUEST_METHOD_POST,
117
+ )
118
+
119
+ return OrganizationDomain.model_validate(response)
120
+
121
+ def delete_organization_domain(self, organization_domain_id: str) -> None:
122
+ self._http_client.request(
123
+ f"organization_domains/{organization_domain_id}",
124
+ method=REQUEST_METHOD_DELETE,
125
+ )
126
+
127
+
128
+ class AsyncOrganizationDomains:
129
+ """Offers async methods for managing organization domains."""
130
+
131
+ _http_client: AsyncHTTPClient
132
+ _client_configuration: ClientConfiguration
133
+
134
+ def __init__(
135
+ self,
136
+ http_client: AsyncHTTPClient,
137
+ client_configuration: ClientConfiguration,
138
+ ):
139
+ self._http_client = http_client
140
+ self._client_configuration = client_configuration
141
+
142
+ async def get_organization_domain(
143
+ self, organization_domain_id: str
144
+ ) -> OrganizationDomain:
145
+ response = await self._http_client.request(
146
+ f"organization_domains/{organization_domain_id}",
147
+ method=REQUEST_METHOD_GET,
148
+ )
149
+
150
+ return OrganizationDomain.model_validate(response)
151
+
152
+ async def create_organization_domain(
153
+ self,
154
+ organization_id: str,
155
+ domain: str,
156
+ ) -> OrganizationDomain:
157
+ response = await self._http_client.request(
158
+ "organization_domains",
159
+ method=REQUEST_METHOD_POST,
160
+ json={"organization_id": organization_id, "domain": domain},
161
+ )
162
+
163
+ return OrganizationDomain.model_validate(response)
164
+
165
+ async def verify_organization_domain(
166
+ self, organization_domain_id: str
167
+ ) -> OrganizationDomain:
168
+ response = await self._http_client.request(
169
+ f"organization_domains/{organization_domain_id}/verify",
170
+ method=REQUEST_METHOD_POST,
171
+ )
172
+
173
+ return OrganizationDomain.model_validate(response)
174
+
175
+ async def delete_organization_domain(self, organization_domain_id: str) -> None:
176
+ await self._http_client.request(
177
+ f"organization_domains/{organization_domain_id}",
178
+ method=REQUEST_METHOD_DELETE,
179
+ )
@@ -38,7 +38,7 @@ from workos.types.events.organization_domain_verification_failed_payload import
38
38
  )
39
39
  from workos.types.events.session_created_payload import SessionCreatedPayload
40
40
  from workos.types.organizations.organization_common import OrganizationCommon
41
- from workos.types.organizations.organization_domain import OrganizationDomain
41
+ from workos.types.organization_domains import OrganizationDomain
42
42
  from workos.types.roles.role import EventRole
43
43
  from workos.types.sso.connection import Connection
44
44
  from workos.types.user_management.email_verification import (
@@ -193,6 +193,18 @@ class OrganizationDomainVerifiedEvent(EventModel[OrganizationDomain]):
193
193
  event: Literal["organization_domain.verified"]
194
194
 
195
195
 
196
+ class OrganizationDomainCreatedEvent(EventModel[OrganizationDomain]):
197
+ event: Literal["organization_domain.created"]
198
+
199
+
200
+ class OrganizationDomainUpdatedEvent(EventModel[OrganizationDomain]):
201
+ event: Literal["organization_domain.updated"]
202
+
203
+
204
+ class OrganizationDomainDeletedEvent(EventModel[OrganizationDomain]):
205
+ event: Literal["organization_domain.deleted"]
206
+
207
+
196
208
  class OrganizationMembershipCreatedEvent(EventModel[OrganizationMembership]):
197
209
  event: Literal["organization_membership.created"]
198
210
 
@@ -272,6 +284,9 @@ Event = Annotated[
272
284
  OrganizationCreatedEvent,
273
285
  OrganizationDeletedEvent,
274
286
  OrganizationUpdatedEvent,
287
+ OrganizationDomainCreatedEvent,
288
+ OrganizationDomainDeletedEvent,
289
+ OrganizationDomainUpdatedEvent,
275
290
  OrganizationDomainVerificationFailedEvent,
276
291
  OrganizationDomainVerifiedEvent,
277
292
  OrganizationMembershipCreatedEvent,
@@ -37,7 +37,7 @@ from workos.types.events.organization_domain_verification_failed_payload import
37
37
  )
38
38
  from workos.types.events.session_created_payload import SessionCreatedPayload
39
39
  from workos.types.organizations.organization_common import OrganizationCommon
40
- from workos.types.organizations.organization_domain import OrganizationDomain
40
+ from workos.types.organization_domains import OrganizationDomain
41
41
  from workos.types.roles.role import EventRole
42
42
  from workos.types.sso.connection import Connection
43
43
  from workos.types.user_management.email_verification import (
@@ -36,6 +36,9 @@ EventType = Literal[
36
36
  "organization.updated",
37
37
  "organization_domain.verification_failed",
38
38
  "organization_domain.verified",
39
+ "organization_domain.created",
40
+ "organization_domain.deleted",
41
+ "organization_domain.updated",
39
42
  "organization_membership.created",
40
43
  "organization_membership.deleted",
41
44
  "organization_membership.updated",
@@ -1,6 +1,6 @@
1
1
  from typing import Literal
2
2
  from workos.types.workos_model import WorkOSModel
3
- from workos.types.organizations.organization_domain import OrganizationDomain
3
+ from workos.types.organization_domains import OrganizationDomain
4
4
  from workos.typing.literals import LiteralOrUntyped
5
5
 
6
6
 
@@ -33,6 +33,7 @@ from workos.types.mfa import AuthenticationFactor
33
33
  from workos.types.organizations import Organization
34
34
  from workos.types.sso import ConnectionWithDomains
35
35
  from workos.types.user_management import Invitation, OrganizationMembership, User
36
+ from workos.types.vault import ObjectDigest
36
37
  from workos.types.workos_model import WorkOSModel
37
38
  from workos.utils.request_helper import DEFAULT_LIST_RESPONSE_LIMIT
38
39
 
@@ -51,6 +52,7 @@ ListableResource = TypeVar(
51
52
  AuthorizationResource,
52
53
  AuthorizationResourceType,
53
54
  User,
55
+ ObjectDigest,
54
56
  Warrant,
55
57
  WarrantQueryResult,
56
58
  )
@@ -0,0 +1 @@
1
+ from .organization_domain import *
@@ -13,3 +13,6 @@ class OrganizationDomain(WorkOSModel):
13
13
  ] = None
14
14
  verification_strategy: Optional[LiteralOrUntyped[Literal["manual", "dns"]]] = None
15
15
  verification_token: Optional[str] = None
16
+ verification_prefix: Optional[str] = None
17
+ created_at: str
18
+ updated_at: str
@@ -1,4 +1,6 @@
1
1
  from .domain_data_input import *
2
2
  from .organization_common import *
3
- from .organization_domain import *
4
3
  from .organization import *
4
+
5
+ # re-exported for backwards compatibility, can be removed after version 6.0.0
6
+ from workos.types.organization_domains import OrganizationDomain
@@ -2,7 +2,7 @@ from dataclasses import field
2
2
  from typing import Optional, Sequence
3
3
  from workos.types.metadata import Metadata
4
4
  from workos.types.organizations.organization_common import OrganizationCommon
5
- from workos.types.organizations.organization_domain import OrganizationDomain
5
+ from workos.types.organization_domains import OrganizationDomain
6
6
 
7
7
 
8
8
  class Organization(OrganizationCommon):
@@ -1,6 +1,6 @@
1
1
  from typing import Literal, Sequence
2
2
  from workos.types.workos_model import WorkOSModel
3
- from workos.types.organizations.organization_domain import OrganizationDomain
3
+ from workos.types.organization_domains import OrganizationDomain
4
4
 
5
5
 
6
6
  class OrganizationCommon(WorkOSModel):
@@ -0,0 +1,2 @@
1
+ from .key import *
2
+ from .object import *
@@ -0,0 +1,25 @@
1
+ from typing import Dict
2
+ from pydantic import BaseModel, RootModel
3
+ from workos.types.workos_model import WorkOSModel
4
+
5
+
6
+ class KeyContext(RootModel[Dict[str, str]]):
7
+ pass
8
+
9
+
10
+ class DataKey(WorkOSModel):
11
+ id: str
12
+ key: str
13
+
14
+
15
+ class DataKeyPair(WorkOSModel):
16
+ context: KeyContext
17
+ data_key: DataKey
18
+ encrypted_keys: str
19
+
20
+
21
+ class DecodedKeys(BaseModel):
22
+ iv: bytes
23
+ tag: bytes
24
+ keys: str # Base64-encoded string
25
+ ciphertext: bytes
@@ -0,0 +1,38 @@
1
+ from typing import Optional
2
+
3
+ from workos.types.workos_model import WorkOSModel
4
+ from workos.types.vault import KeyContext
5
+
6
+
7
+ class ObjectDigest(WorkOSModel):
8
+ id: str
9
+ name: str
10
+ updated_at: str
11
+
12
+
13
+ class ObjectUpdateBy(WorkOSModel):
14
+ id: str
15
+ name: str
16
+
17
+
18
+ class ObjectMetadata(WorkOSModel):
19
+ context: KeyContext
20
+ environment_id: str
21
+ id: str
22
+ key_id: str
23
+ updated_at: str
24
+ updated_by: ObjectUpdateBy
25
+ version_id: str
26
+
27
+
28
+ class VaultObject(WorkOSModel):
29
+ id: str
30
+ metadata: ObjectMetadata
31
+ name: str
32
+ value: Optional[str] = None
33
+
34
+
35
+ class ObjectVersion(WorkOSModel):
36
+ created_at: str
37
+ current_version: bool
38
+ id: str
@@ -38,7 +38,7 @@ from workos.types.events.organization_domain_verification_failed_payload import
38
38
  )
39
39
  from workos.types.events.session_created_payload import SessionCreatedPayload
40
40
  from workos.types.organizations.organization_common import OrganizationCommon
41
- from workos.types.organizations.organization_domain import OrganizationDomain
41
+ from workos.types.organization_domains import OrganizationDomain
42
42
  from workos.types.roles.role import EventRole
43
43
  from workos.types.sso.connection import Connection
44
44
  from workos.types.user_management.email_verification import (
@@ -0,0 +1,39 @@
1
+ import os
2
+ from typing import Optional, Dict
3
+ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
4
+ from cryptography.hazmat.backends import default_backend
5
+
6
+
7
+ class CryptoProvider:
8
+ def encrypt(
9
+ self, plaintext: bytes, key: bytes, iv: bytes, aad: Optional[bytes]
10
+ ) -> Dict[str, bytes]:
11
+ encryptor = Cipher(
12
+ algorithms.AES(key), modes.GCM(iv), backend=default_backend()
13
+ ).encryptor()
14
+
15
+ if aad:
16
+ encryptor.authenticate_additional_data(aad)
17
+
18
+ ciphertext = encryptor.update(plaintext) + encryptor.finalize()
19
+ return {"ciphertext": ciphertext, "iv": iv, "tag": encryptor.tag}
20
+
21
+ def decrypt(
22
+ self,
23
+ ciphertext: bytes,
24
+ key: bytes,
25
+ iv: bytes,
26
+ tag: bytes,
27
+ aad: Optional[bytes] = None,
28
+ ) -> bytes:
29
+ decryptor = Cipher(
30
+ algorithms.AES(key), modes.GCM(iv, tag), backend=default_backend()
31
+ ).decryptor()
32
+
33
+ if aad:
34
+ decryptor.authenticate_additional_data(aad)
35
+
36
+ return decryptor.update(ciphertext) + decryptor.finalize()
37
+
38
+ def random_bytes(self, n: int) -> bytes:
39
+ return os.urandom(n)
workos/vault.py ADDED
@@ -0,0 +1,515 @@
1
+ import base64
2
+ from typing import Optional, Protocol, Sequence, Tuple
3
+ from workos.types.vault import VaultObject, ObjectVersion, ObjectDigest, ObjectMetadata
4
+ from workos.types.vault.key import DataKey, DataKeyPair, KeyContext, DecodedKeys
5
+ from workos.types.list_resource import (
6
+ ListArgs,
7
+ ListMetadata,
8
+ ListPage,
9
+ WorkOSListResource,
10
+ )
11
+ from workos.utils.http_client import SyncHTTPClient
12
+ from workos.utils.pagination_order import PaginationOrder
13
+ from workos.utils.request_helper import (
14
+ DEFAULT_LIST_RESPONSE_LIMIT,
15
+ REQUEST_METHOD_DELETE,
16
+ REQUEST_METHOD_GET,
17
+ REQUEST_METHOD_POST,
18
+ REQUEST_METHOD_PUT,
19
+ RequestHelper,
20
+ )
21
+ from workos.utils.crypto_provider import CryptoProvider
22
+
23
+ DEFAULT_RESPONSE_LIMIT = DEFAULT_LIST_RESPONSE_LIMIT
24
+
25
+ VaultObjectList = WorkOSListResource[ObjectDigest, ListArgs, ListMetadata]
26
+
27
+
28
+ class VaultModule(Protocol):
29
+ def read_object(self, *, object_id: str) -> VaultObject:
30
+ """
31
+ Get a Vault object with the value decrypted.
32
+
33
+ Kwargs:
34
+ object_id (str): The unique identifier for the object.
35
+ Returns:
36
+ VaultObject: A vault object with metadata, name and decrypted value.
37
+ """
38
+ ...
39
+
40
+ def list_objects(
41
+ self,
42
+ *,
43
+ limit: int = DEFAULT_RESPONSE_LIMIT,
44
+ before: Optional[str] = None,
45
+ after: Optional[str] = None,
46
+ ) -> VaultObjectList:
47
+ """
48
+ Gets a list of encrypted Vault objects.
49
+
50
+ Kwargs:
51
+ limit (int): The maximum number of objects to return. (Optional)
52
+ before (str): A cursor to return resources before. (Optional)
53
+ after (str): A cursor to return resources after. (Optional)
54
+
55
+ Returns:
56
+ VaultObjectList: A list of vault objects with built-in pagination iterator.
57
+ """
58
+ ...
59
+
60
+ def list_object_versions(
61
+ self,
62
+ *,
63
+ object_id: str,
64
+ ) -> Sequence[ObjectVersion]:
65
+ """
66
+ Gets a list of versions for a specific Vault object.
67
+
68
+ Kwargs:
69
+ object_id (str): The unique identifier for the object.
70
+
71
+ Returns:
72
+ Sequence[ObjectVersion]: A list of object versions.
73
+ """
74
+ ...
75
+
76
+ def create_object(
77
+ self,
78
+ *,
79
+ name: str,
80
+ value: str,
81
+ key_context: KeyContext,
82
+ ) -> ObjectMetadata:
83
+ """
84
+ Create a new Vault encrypted object.
85
+
86
+ Kwargs:
87
+ name (str): The name of the object.
88
+ value (str): The value to encrypt and store.
89
+ key_context (KeyContext): A set of key-value dictionary pairs that determines which root keys to use when encrypting data.
90
+
91
+ Returns:
92
+ VaultObject: The created vault object.
93
+ """
94
+ ...
95
+
96
+ def update_object(
97
+ self,
98
+ *,
99
+ object_id: str,
100
+ value: str,
101
+ version_check: Optional[str] = None,
102
+ ) -> VaultObject:
103
+ """
104
+ Update an existing Vault object.
105
+
106
+ Kwargs:
107
+ object_id (str): The unique identifier for the object.
108
+ value (str): The new value to encrypt and store.
109
+ version_check (str): A version of the object to prevent clobbering of data during concurrent updates. (Optional)
110
+
111
+ Returns:
112
+ VaultObject: The updated vault object.
113
+ """
114
+ ...
115
+
116
+ def delete_object(
117
+ self,
118
+ *,
119
+ object_id: str,
120
+ ) -> None:
121
+ """
122
+ Permanently delete a Vault encrypted object. Warning: this cannont be undone.
123
+
124
+ Kwargs:
125
+ object_id (str): The unique identifier for the object.
126
+ """
127
+ ...
128
+
129
+ def create_data_key(self, *, key_context: KeyContext) -> DataKeyPair:
130
+ """
131
+ Generate a data key for local encryption based on the provided key context.
132
+ The encrypted data key MUST be stored by the application, as it cannot be retrieved after generation.
133
+
134
+ Kwargs:
135
+ key_context (KeyContext): A set of key-value dictionary pairs that determines which root keys to use when encrypting data.
136
+ """
137
+ ...
138
+
139
+ def decrypt_data_key(
140
+ self,
141
+ *,
142
+ keys: str,
143
+ ) -> DataKey:
144
+ """
145
+ Decrypt encrypted data keys that were previously generated by create_data_key.
146
+
147
+ This method takes the encrypted data key blob and uses the WorkOS Vault service
148
+ to decrypt it, returning the plaintext data key that can be used for local
149
+ encryption/decryption operations.
150
+
151
+ Kwargs:
152
+ keys (str): The base64-encoded encrypted data key blob returned by create_data_key.
153
+
154
+ Returns:
155
+ DataKey: The decrypted data key containing the key ID and the plaintext key material.
156
+ """
157
+ ...
158
+
159
+ def encrypt(
160
+ self,
161
+ *,
162
+ data: str,
163
+ key_context: KeyContext,
164
+ associated_data: Optional[str] = None,
165
+ ) -> str:
166
+ """
167
+ Encrypt data locally using AES-GCM with a data key derived from the provided context.
168
+
169
+ This method generates a new data key for each encryption operation, ensuring that
170
+ the same plaintext will produce different ciphertext each time it's encrypted.
171
+ The encrypted data key is embedded in the result so it can be decrypted later.
172
+
173
+ Kwargs:
174
+ data (str): The plaintext data to encrypt.
175
+ key_context (KeyContext): A set of key-value dictionary pairs that determines which root keys to use when encrypting data.
176
+ associated_data (str): Additional authenticated data (AAD) that will be authenticated but not encrypted. (Optional)
177
+
178
+ Returns:
179
+ str: Base64-encoded encrypted data containing the IV, authentication tag, encrypted data key, and ciphertext.
180
+ """
181
+ ...
182
+
183
+ def decrypt(
184
+ self, *, encrypted_data: str, associated_data: Optional[str] = None
185
+ ) -> str:
186
+ """
187
+ Decrypt data that was previously encrypted using the encrypt method.
188
+
189
+ This method extracts the encrypted data key from the encrypted payload,
190
+ decrypts it using the WorkOS Vault service, and then uses the resulting
191
+ data key to decrypt the actual data using AES-GCM.
192
+
193
+ Kwargs:
194
+ encrypted_data (str): The base64-encoded encrypted data returned by the encrypt method.
195
+ associated_data (str): The same additional authenticated data (AAD) that was used during encryption, if any. (Optional)
196
+
197
+ Returns:
198
+ str: The original plaintext data.
199
+
200
+ Raises:
201
+ ValueError: If the encrypted_data format is invalid or if associated_data doesn't match what was used during encryption.
202
+ cryptography.exceptions.InvalidTag: If the authentication tag verification fails (data has been tampered with).
203
+ """
204
+ ...
205
+
206
+
207
+ class Vault(VaultModule):
208
+ _http_client: SyncHTTPClient
209
+ _crypto_provider: CryptoProvider
210
+
211
+ def __init__(self, http_client: SyncHTTPClient):
212
+ self._http_client = http_client
213
+ self._crypto_provider = CryptoProvider()
214
+
215
+ def read_object(
216
+ self,
217
+ *,
218
+ object_id: str,
219
+ ) -> VaultObject:
220
+ if not object_id:
221
+ raise ValueError("Incomplete arguments: 'object_id' is a required argument")
222
+
223
+ response = self._http_client.request(
224
+ RequestHelper.build_parameterized_url(
225
+ "vault/v1/kv/{object_id}",
226
+ object_id=object_id,
227
+ ),
228
+ method=REQUEST_METHOD_GET,
229
+ )
230
+
231
+ return VaultObject.model_validate(response)
232
+
233
+ def list_objects(
234
+ self,
235
+ *,
236
+ limit: int = DEFAULT_RESPONSE_LIMIT,
237
+ before: Optional[str] = None,
238
+ after: Optional[str] = None,
239
+ ) -> VaultObjectList:
240
+ list_params: ListArgs = {
241
+ "limit": limit,
242
+ "before": before,
243
+ "after": after,
244
+ }
245
+
246
+ response = self._http_client.request(
247
+ "vault/v1/kv",
248
+ method=REQUEST_METHOD_GET,
249
+ params=list_params,
250
+ )
251
+
252
+ # Ensure object field is present
253
+ response_dict = dict(response)
254
+ if "object" not in response_dict:
255
+ response_dict["object"] = "list"
256
+
257
+ return VaultObjectList(
258
+ list_method=self.list_objects,
259
+ list_args=list_params,
260
+ **ListPage[ObjectDigest](**response_dict).model_dump(),
261
+ )
262
+
263
+ def list_object_versions(
264
+ self,
265
+ *,
266
+ object_id: str,
267
+ ) -> Sequence[ObjectVersion]:
268
+ response = self._http_client.request(
269
+ RequestHelper.build_parameterized_url(
270
+ "vault/v1/kv/{object_id}/versions",
271
+ object_id=object_id,
272
+ ),
273
+ method=REQUEST_METHOD_GET,
274
+ )
275
+
276
+ return [
277
+ ObjectVersion.model_validate(version)
278
+ for version in response.get("data", [])
279
+ ]
280
+
281
+ def create_object(
282
+ self,
283
+ *,
284
+ name: str,
285
+ value: str,
286
+ key_context: KeyContext,
287
+ ) -> ObjectMetadata:
288
+ if not name or not value:
289
+ raise ValueError(
290
+ "Incomplete arguments: 'name' and 'value' are required arguments"
291
+ )
292
+
293
+ request_data = {
294
+ "name": name,
295
+ "value": value,
296
+ "key_context": key_context,
297
+ }
298
+
299
+ response = self._http_client.request(
300
+ "vault/v1/kv",
301
+ method=REQUEST_METHOD_POST,
302
+ json=request_data,
303
+ )
304
+
305
+ return ObjectMetadata.model_validate(response)
306
+
307
+ def update_object(
308
+ self,
309
+ *,
310
+ object_id: str,
311
+ value: str,
312
+ version_check: Optional[str] = None,
313
+ ) -> VaultObject:
314
+ if not object_id:
315
+ raise ValueError("Incomplete arguments: 'object_id' is a required argument")
316
+
317
+ request_data = {
318
+ "value": value,
319
+ }
320
+ if version_check is not None:
321
+ request_data["version_check"] = version_check
322
+
323
+ response = self._http_client.request(
324
+ RequestHelper.build_parameterized_url(
325
+ "vault/v1/kv/{object_id}",
326
+ object_id=object_id,
327
+ ),
328
+ method=REQUEST_METHOD_PUT,
329
+ json=request_data,
330
+ )
331
+
332
+ return VaultObject.model_validate(response)
333
+
334
+ def delete_object(
335
+ self,
336
+ *,
337
+ object_id: str,
338
+ ) -> None:
339
+ if not object_id:
340
+ raise ValueError("Incomplete arguments: 'object_id' is a required argument")
341
+
342
+ self._http_client.request(
343
+ RequestHelper.build_parameterized_url(
344
+ "vault/v1/kv/{object_id}",
345
+ object_id=object_id,
346
+ ),
347
+ method=REQUEST_METHOD_DELETE,
348
+ )
349
+
350
+ def create_data_key(self, *, key_context: KeyContext) -> DataKeyPair:
351
+ request_data = {
352
+ "context": key_context,
353
+ }
354
+
355
+ response = self._http_client.request(
356
+ "vault/v1/keys/data-key",
357
+ method=REQUEST_METHOD_POST,
358
+ json=request_data,
359
+ )
360
+
361
+ return DataKeyPair.model_validate(
362
+ {
363
+ "context": response["context"],
364
+ "data_key": {"id": response["id"], "key": response["data_key"]},
365
+ "encrypted_keys": response["encrypted_keys"],
366
+ }
367
+ )
368
+
369
+ def decrypt_data_key(
370
+ self,
371
+ *,
372
+ keys: str,
373
+ ) -> DataKey:
374
+ request_data = {
375
+ "keys": keys,
376
+ }
377
+
378
+ response = self._http_client.request(
379
+ "vault/v1/keys/decrypt",
380
+ method=REQUEST_METHOD_POST,
381
+ json=request_data,
382
+ )
383
+
384
+ return DataKey.model_validate(
385
+ {"id": response["id"], "key": response["data_key"]}
386
+ )
387
+
388
+ def encrypt(
389
+ self,
390
+ *,
391
+ data: str,
392
+ key_context: KeyContext,
393
+ associated_data: Optional[str] = None,
394
+ ) -> str:
395
+ key_pair = self.create_data_key(key_context=key_context)
396
+
397
+ key = self._base64_to_bytes(key_pair.data_key.key)
398
+ key_blob = self._base64_to_bytes(key_pair.encrypted_keys)
399
+ prefix_len_buffer = self._encode_u32(len(key_blob))
400
+ aad_buffer = associated_data.encode("utf-8") if associated_data else None
401
+ iv = self._crypto_provider.random_bytes(12)
402
+
403
+ result = self._crypto_provider.encrypt(
404
+ data.encode("utf-8"), key, iv, aad_buffer
405
+ )
406
+
407
+ combined = (
408
+ result["iv"]
409
+ + result["tag"]
410
+ + prefix_len_buffer
411
+ + key_blob
412
+ + result["ciphertext"]
413
+ )
414
+
415
+ return self._bytes_to_base64(combined)
416
+
417
+ def decrypt(
418
+ self, *, encrypted_data: str, associated_data: Optional[str] = None
419
+ ) -> str:
420
+ decoded = self._decode(encrypted_data)
421
+ data_key = self.decrypt_data_key(keys=decoded.keys)
422
+
423
+ key = self._base64_to_bytes(data_key.key)
424
+ aad_buffer = associated_data.encode("utf-8") if associated_data else None
425
+
426
+ decrypted_bytes = self._crypto_provider.decrypt(
427
+ ciphertext=decoded.ciphertext,
428
+ key=key,
429
+ iv=decoded.iv,
430
+ tag=decoded.tag,
431
+ aad=aad_buffer,
432
+ )
433
+
434
+ return decrypted_bytes.decode("utf-8")
435
+
436
+ def _base64_to_bytes(self, data: str) -> bytes:
437
+ return base64.b64decode(data)
438
+
439
+ def _bytes_to_base64(self, data: bytes) -> str:
440
+ return base64.b64encode(data).decode("utf-8")
441
+
442
+ def _encode_u32(self, value: int) -> bytes:
443
+ """
444
+ Encode a 32-bit unsigned integer as LEB128.
445
+
446
+ Returns:
447
+ bytes: LEB128-encoded representation of the input value.
448
+ """
449
+ if value < 0 or value > 0xFFFFFFFF:
450
+ raise ValueError("Value must be a 32-bit unsigned integer")
451
+
452
+ encoded = bytearray()
453
+ while True:
454
+ byte = value & 0x7F
455
+ value >>= 7
456
+ if value != 0:
457
+ byte |= 0x80 # Set continuation bit
458
+ encoded.append(byte)
459
+ if value == 0:
460
+ break
461
+
462
+ return bytes(encoded)
463
+
464
+ def _decode(self, encrypted_data_b64: str) -> DecodedKeys:
465
+ """
466
+ This function extracts IV, tag, keyBlobLength, keyBlob, and ciphertext
467
+ from a base64-encoded payload.
468
+ Encoding format: [IV][TAG][4B Length][keyBlob][ciphertext]
469
+ """
470
+ try:
471
+ payload = base64.b64decode(encrypted_data_b64)
472
+ except Exception as e:
473
+ raise ValueError("Base64 decoding failed") from e
474
+
475
+ iv = payload[0:12]
476
+ tag = payload[12:28]
477
+
478
+ try:
479
+ key_len, leb_len = self._decode_u32(payload[28:])
480
+ except Exception as e:
481
+ raise ValueError("Failed to decode key length") from e
482
+
483
+ keys_index = 28 + leb_len
484
+ keys_end = keys_index + key_len
485
+ keys_slice = payload[keys_index:keys_end]
486
+ keys = base64.b64encode(keys_slice).decode("utf-8")
487
+ ciphertext = payload[keys_end:]
488
+
489
+ return DecodedKeys(iv=iv, tag=tag, keys=keys, ciphertext=ciphertext)
490
+
491
+ def _decode_u32(self, buf: bytes) -> Tuple[int, int]:
492
+ """
493
+ Decode an unsigned LEB128-encoded 32-bit integer from bytes.
494
+
495
+ Returns:
496
+ (value, length_consumed)
497
+
498
+ Raises:
499
+ ValueError if decoding fails or overflows.
500
+ """
501
+ res = 0
502
+ bit = 0
503
+
504
+ for i, b in enumerate(buf):
505
+ if i > 4:
506
+ raise ValueError("LEB128 integer overflow (was more than 4 bytes)")
507
+
508
+ res |= (b & 0x7F) << (7 * bit)
509
+
510
+ if (b & 0x80) == 0:
511
+ return res, i + 1
512
+
513
+ bit += 1
514
+
515
+ raise ValueError("LEB128 integer not found")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: workos
3
- Version: 5.23.0
3
+ Version: 5.26.0
4
4
  Summary: WorkOS Python Client
5
5
  Home-page: https://github.com/workos-inc/workos-python
6
6
  Author: WorkOS
@@ -1,15 +1,16 @@
1
- workos/__about__.py,sha256=gPnfGwbokmJccKOueu0QsNoiFGUYhHwOVX1_mLa4xzw,406
1
+ workos/__about__.py,sha256=XjdHlLqPEJ0a5evP3CCUorp0ckGip4qzzY2V8gM6xXg,406
2
2
  workos/__init__.py,sha256=hOdbO_MJCvpLx8EbRjQg-fvFAB-glJmrmxUZK8kWG0k,167
3
- workos/_base_client.py,sha256=t69Nb3zxo3wygI3JtbPdZMGvIuRPsZx_xZANC5K8dn8,3429
3
+ workos/_base_client.py,sha256=YWLXBpd0YeID3WKYZkKa4l9ZuB9e6HgdLmPKZIzXsME,3599
4
4
  workos/_client_configuration.py,sha256=g3eXhtrEMN6CW0hZ5uHb2PmLurXjyBkWZeQYMPeJD6s,222
5
- workos/async_client.py,sha256=ezl6pO2I2eGZnq0jrqD7-C7JKfvBqrsqq4T0cbYndPE,3756
5
+ workos/async_client.py,sha256=c_lP7y49k3FEx0S6We8PrEw3PhTkD0VHyHJaKgc51HU,4358
6
6
  workos/audit_logs.py,sha256=bYoAoNO4FRSaT34UxiVkgTXCVH8givcS2YGhH_9O3NA,3983
7
- workos/client.py,sha256=ESweUKW2ju5dPGFCTUMxjVYgh2txoZ3ZVbxy81i0JcI,3747
7
+ workos/client.py,sha256=hIm87iNtKfwQ93H5aRXnhTqUJIOzUEG1GX0jdLBLAYc,4345
8
8
  workos/directory_sync.py,sha256=6Z1gHz1LWNy56EtkXwNm6jhRRcvsJ7ASeDLy_Q1oKM0,14601
9
9
  workos/events.py,sha256=b4JIzMbd5LlVtpOMKVojC70RCHAgmLN3nJ62_2U0GwI,3892
10
10
  workos/exceptions.py,sha256=eoy-T4We98HKZn0UZu33fPzhm4DwafzwLeg3juhC6FE,1732
11
11
  workos/fga.py,sha256=qjZrdkXKwJDLVTMMrOADxyXRDkswto4kGIdtTjtS3hw,21008
12
12
  workos/mfa.py,sha256=J8eOr4ZEmK0TPFKD7pabSalgCFCyg3XJY1stu28_8Vw,6862
13
+ workos/organization_domains.py,sha256=um-dm54SIs2Kd2FxqxVjIlynlenAG9NamQmNVUGOQ0k,5464
13
14
  workos/organizations.py,sha256=ugPRhwN8cN2O6qOCf7wj8Wus-oeRKXlNe2642PSl_n4,12266
14
15
  workos/passwordless.py,sha256=NGXDoxomBkrIml8-VHXH1HvCFMqotQ-YhRobUQXpVZs,3203
15
16
  workos/portal.py,sha256=lzf3fnOor4AyVdHCHMuJzVSpAC9LWWdC5sZIRtCsb0c,2443
@@ -17,10 +18,11 @@ workos/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
18
  workos/session.py,sha256=CVada-nKRFv9m2-mcghR5VBOguGU76iDCDgQlksOOrQ,11912
18
19
  workos/sso.py,sha256=ZBC3y-IRmxG0jPd0BOj7s7XQkXJoTLUg1fx-h3Gfy4g,13541
19
20
  workos/user_management.py,sha256=qy21HxYVO40xo7TvCGVxvGWdYIFHZTVnUJTpCQIN2ko,77113
21
+ workos/vault.py,sha256=SJXr3nJ03qJFuf30FjevMD6LLlDNX3MGaKlYGgICRRE,15657
20
22
  workos/webhooks.py,sha256=CuwBxh6va9VZFVSXOknveGt6CCGDF3em07a-J12DbXI,4790
21
23
  workos/widgets.py,sha256=bfbR0hQOHZabbgGL2ekD5sY1sjiUoWBTdrBd_a6WmBc,1721
22
24
  workos/types/__init__.py,sha256=aYScTXq5jOyp0AYvdWffaj5-zdDuNtCCJtbzt5GM19k,267
23
- workos/types/list_resource.py,sha256=MLfmtevGVpwb38EurJiD5NO-H5mADEp4DitZMiacSO0,6508
25
+ workos/types/list_resource.py,sha256=6N9OoaFsWPCXEX9plVONODxed-Yx6RaX1ga1b15ENIA,6570
24
26
  workos/types/metadata.py,sha256=uUqDkGJGyFY3H4JZObSiCfn4jKBue5CBhOqv79TI1n0,52
25
27
  workos/types/workos_model.py,sha256=bV_p3baadcUJOU_7f6ysZ6KXhpt3E_93spuZnfJs9vc,735
26
28
  workos/types/audit_logs/__init__.py,sha256=daPn8wAVEnlM1fCpOsy3dVZV_0YEp8bA1T_nhk5-pU8,211
@@ -45,11 +47,11 @@ workos/types/events/directory_group_with_previous_attributes.py,sha256=13VLNhdJZ
45
47
  workos/types/events/directory_payload.py,sha256=tRo3f9g8VoYertSUPAR25iGDyGLr2Dtb2mTkl73PAeA,503
46
48
  workos/types/events/directory_payload_with_legacy_fields.py,sha256=jk9nLmRqgllVkBG4EU3uTgcDOhCNptHgCh93U7aBAYE,1005
47
49
  workos/types/events/directory_user_with_previous_attributes.py,sha256=PhnO3WakBxAvnlOGf0UB0bvoppUYlwLyU-g9X_pPdko,244
48
- workos/types/events/event.py,sha256=OZfsPNDD46-6wWcnAE2HkT5Lt23vGj3o8wz7XfQE2vY,9344
49
- workos/types/events/event_model.py,sha256=r5B_lZ7QXgoI7SGyQF7xNaEEE-ATMRet83pMYYJANuo,3735
50
- workos/types/events/event_type.py,sha256=jzZ5rlYXKmrHzbnymeMiIqmVF7i1Yvp76zqkCYl6Puo,1585
50
+ workos/types/events/event.py,sha256=4E-71v38J1Udt0qFz9k17V6HmNj9Lgz-mmS-524ysIs,9817
51
+ workos/types/events/event_model.py,sha256=TuCRgjgTWnTvwL3NTR9FBGuF7WO34OhsbtMGKss5QKA,3722
52
+ workos/types/events/event_type.py,sha256=NIVHMahETiKeFJfZGi-ptHQH7czmRY4tChnuMU0OxWw,1690
51
53
  workos/types/events/list_filters.py,sha256=P04zmRynx9VPqNX_MBXA-3KA6flPZJogtIUqTI7w9Eg,305
52
- workos/types/events/organization_domain_verification_failed_payload.py,sha256=26reKTFxdriOo6fF6MVkYx0s867E-bproKTbwLZcUpE,483
54
+ workos/types/events/organization_domain_verification_failed_payload.py,sha256=b4wX8HVbL9Nx6fCjOXkZg9eLc-Bv6YqAjMap1f7UvFc,470
53
55
  workos/types/events/previous_attributes.py,sha256=DxolwLwzcnG8r_W6rh5BT29iDfSVsIELvRYJ0NCrNn0,72
54
56
  workos/types/events/session_created_payload.py,sha256=F4eKjmetgyRIluNBDUmB2OXq8hDWEVjALJ4rrT2IHJs,462
55
57
  workos/types/fga/__init__.py,sha256=mVb3gvhvK93PAosSgO1RlNmxYX4zIxVDcZZQ8Jyejuw,151
@@ -65,12 +67,13 @@ workos/types/mfa/authentication_challenge_verification_response.py,sha256=5HxsMJ
65
67
  workos/types/mfa/authentication_factor.py,sha256=92Cq9MLwBUXfowzCv2u9ZnoH9tVgDm16jjmelN7BOGs,2021
66
68
  workos/types/mfa/authentication_factor_totp_and_challenge_response.py,sha256=Ix_DqF7eQ-x6Up8C_0wzvAXXyDY876nobRuiXXL8nbc,541
67
69
  workos/types/mfa/enroll_authentication_factor_type.py,sha256=l_w4co5BdmfglII5YAQiyL-kdAw8KiiOsYaDhn8lGWE,227
68
- workos/types/organizations/__init__.py,sha256=tS8oObLGCyk2QnaMtoaaGKoLbbzSylL_8qovsPF6Rqc,131
70
+ workos/types/organization_domains/__init__.py,sha256=fpNRKfzZ0p1FybwQG4L-YY12nFPTCJjD4j60OJI5fXE,35
71
+ workos/types/organization_domains/organization_domain.py,sha256=PkmdVVQi6h94xHWLJt0SFGgiGEVoyxwiPD-WwQ1naWs,614
72
+ workos/types/organizations/__init__.py,sha256=uE2qD2MOebPs-_BerqenTqmu4I4DI5-CKIY_M8BGwDY,240
69
73
  workos/types/organizations/domain_data_input.py,sha256=BW3iYswF-b2SXip7jwPkmlZhgLReS_VyzUlU8PD4xdw,161
70
74
  workos/types/organizations/list_filters.py,sha256=u-TsEEMVI8IvPvxn_9--k6iYDs4T64RHTY_HY0Fvwlw,179
71
- workos/types/organizations/organization.py,sha256=GNs7Mf4-B4NpKSsE4uD9106kG6e6yz2EImdgSw9X310,533
72
- workos/types/organizations/organization_common.py,sha256=HFrXwia3xV6KkAAfW6zyMcjxXrznv82hFajHVHZdhpM,350
73
- workos/types/organizations/organization_domain.py,sha256=gFumod8dBtTLxmAlD83UuF_96B8lSjwsgwr_OOpvxOY,528
75
+ workos/types/organizations/organization.py,sha256=oVGg-C0blizg7aGVeRTr3vvTRvrn_WPzwaV-LvbQxRo,520
76
+ workos/types/organizations/organization_common.py,sha256=lelq-Id9AGSmosFprFAET_QyXmYR0wHX9-XMsOTEr7s,337
74
77
  workos/types/passwordless/__init__.py,sha256=ZP_XIcGUKXsATb--bfesnsFFbbvg3WYzgqRC_qvW0rw,77
75
78
  workos/types/passwordless/passwordless_session.py,sha256=izmTI5F7qvBdoVodaXP7fnYo_XodG-ygyYTPrCEObTM,293
76
79
  workos/types/passwordless/passwordless_session_type.py,sha256=ltZAV8KFiYDVcxpVt5Hcdc089tB5VETYaa9X6E7Mvoo,75
@@ -101,8 +104,11 @@ workos/types/user_management/screen_hint.py,sha256=DnPgvjRK-20i82v3YPzggna1rc6yO
101
104
  workos/types/user_management/session.py,sha256=pyINOo_a53rxtZ-gGYOZziNHoZzc7s56evKgVAPIgMo,1390
102
105
  workos/types/user_management/user.py,sha256=aXRHsLXnQbXWBPRTdAP9Ym_-D9hjmrp_E4PTPi1gF1s,603
103
106
  workos/types/user_management/user_management_provider_type.py,sha256=UEjtcs9oeDvL9248bFy8nRfzutA6aBfhVMuMByG0qsM,145
107
+ workos/types/vault/__init__.py,sha256=krBuIl8luysrtDf9-b8KTkXOHDOaSsOR-Aao6Wlil0Q,41
108
+ workos/types/vault/key.py,sha256=x30XBplSj9AviDDAB8MdpcULbZvvo2sUzi8RCmZQKxU,453
109
+ workos/types/vault/object.py,sha256=-rk4KovS3eT8T8L3JltYUS0cd2Rg1JKcAX9SOaZO3D8,664
104
110
  workos/types/webhooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
105
- workos/types/webhooks/webhook.py,sha256=IIDhlGTwiNm3xEncSk-OYm0EZsxwXmxDT5_jKx_Bt60,9523
111
+ workos/types/webhooks/webhook.py,sha256=v0Z7Z1eMnjCMR8iWm2KNECv-8nwPdTB8gTZCVfFP0O0,9510
106
112
  workos/types/webhooks/webhook_model.py,sha256=v7Hgtzt0nW_5RaYoB_QGVfElhdjySuG3F1BFjoid36w,404
107
113
  workos/types/webhooks/webhook_payload.py,sha256=GXt31KtyBM-ji5K5p4dBnu46Gh8adQWTq0ye5USB_6g,68
108
114
  workos/types/widgets/__init__.py,sha256=z2Tdlj_bJsRZeJRh4SOFX58PvJdf0LjKnYhrQX1fpME,65
@@ -115,11 +121,12 @@ workos/typing/untyped_literal.py,sha256=wf48_6kZJ-AN3-V2gLC_y5k2tnUvgGnhn89HsfOK
115
121
  workos/typing/webhooks.py,sha256=8GhUnrlGrgQbknh32tVtHxeR8FsXsJesW94CtZiB-_4,534
116
122
  workos/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
117
123
  workos/utils/_base_http_client.py,sha256=KqRHUaDJUfXGxhu6UHLfZVkIBikcvrUZYhm9GBSByB4,7410
124
+ workos/utils/crypto_provider.py,sha256=QeQSR4t9xLlb90kEfl8onVUsf1yCkYq0EjFTxK0mUlk,1182
118
125
  workos/utils/http_client.py,sha256=TM5yMFFExmAE8D2Z43-5O301tRbnylLG0aXO0isGorE,6197
119
126
  workos/utils/pagination_order.py,sha256=_-et1DDJLG0czarTU7op4W6RA0V1f85GNsUgtyRU55Q,70
120
127
  workos/utils/request_helper.py,sha256=NaO16qPPbSNnCeE0fiNKYb8gM-dK_okYVJbLGrEGXz8,793
121
- workos-5.23.0.dist-info/LICENSE,sha256=mU--WL1JzelH2tXpKVoOlpud4cpqKSRTtdArCvYZmb4,1063
122
- workos-5.23.0.dist-info/METADATA,sha256=6axcTXs8vYKZ4CLs32aIC1znvQQGb0If40EnWk30_fk,4187
123
- workos-5.23.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
124
- workos-5.23.0.dist-info/top_level.txt,sha256=ZFskIfue1Tw-JwjyIXRvdsAl9i0DX9VbqmgICXV84Sk,7
125
- workos-5.23.0.dist-info/RECORD,,
128
+ workos-5.26.0.dist-info/LICENSE,sha256=mU--WL1JzelH2tXpKVoOlpud4cpqKSRTtdArCvYZmb4,1063
129
+ workos-5.26.0.dist-info/METADATA,sha256=MohK6HHQVDsilcCLtEwsSRF_ufiHMGCe1puhiVakL60,4187
130
+ workos-5.26.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
131
+ workos-5.26.0.dist-info/top_level.txt,sha256=ZFskIfue1Tw-JwjyIXRvdsAl9i0DX9VbqmgICXV84Sk,7
132
+ workos-5.26.0.dist-info/RECORD,,