workos 1.5.1__py3-none-any.whl → 5.38.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 +1 -1
- workos/__init__.py +3 -7
- workos/_base_client.py +138 -0
- workos/_client_configuration.py +10 -0
- workos/api_keys.py +53 -0
- workos/async_client.py +144 -0
- workos/audit_logs.py +125 -0
- workos/client.py +110 -18
- workos/directory_sync.py +379 -99
- workos/events.py +111 -0
- workos/exceptions.py +53 -26
- workos/fga.py +649 -0
- workos/mfa.py +205 -0
- workos/organization_domains.py +179 -0
- workos/organizations.py +403 -73
- workos/passwordless.py +67 -43
- workos/pipes.py +93 -0
- workos/portal.py +51 -28
- workos/session.py +337 -0
- workos/sso.py +311 -101
- workos/types/__init__.py +4 -0
- workos/types/api_keys/__init__.py +1 -0
- workos/types/api_keys/api_keys.py +20 -0
- workos/types/audit_logs/__init__.py +6 -0
- workos/types/audit_logs/audit_log_event.py +16 -0
- workos/types/audit_logs/audit_log_event_actor.py +12 -0
- workos/types/audit_logs/audit_log_event_context.py +8 -0
- workos/types/audit_logs/audit_log_event_target.py +12 -0
- workos/types/audit_logs/audit_log_export.py +18 -0
- workos/types/audit_logs/audit_log_metadata.py +4 -0
- workos/types/directory_sync/__init__.py +5 -0
- workos/types/directory_sync/directory.py +31 -0
- workos/types/directory_sync/directory_group.py +16 -0
- workos/types/directory_sync/directory_state.py +28 -0
- workos/types/directory_sync/directory_type.py +24 -0
- workos/types/directory_sync/directory_user.py +50 -0
- workos/types/directory_sync/list_filters.py +21 -0
- workos/types/events/__init__.py +13 -0
- workos/types/events/authentication_payload.py +70 -0
- workos/types/events/connection_payload_with_legacy_fields.py +5 -0
- workos/types/events/directory_group_membership_payload.py +9 -0
- workos/types/events/directory_group_with_previous_attributes.py +6 -0
- workos/types/events/directory_payload.py +16 -0
- workos/types/events/directory_payload_with_legacy_fields.py +29 -0
- workos/types/events/directory_user_with_previous_attributes.py +6 -0
- workos/types/events/event.py +324 -0
- workos/types/events/event_model.py +103 -0
- workos/types/events/event_type.py +59 -0
- workos/types/events/list_filters.py +10 -0
- workos/types/events/organization_domain_verification_failed_payload.py +14 -0
- workos/types/events/previous_attributes.py +3 -0
- workos/types/events/session_payload.py +27 -0
- workos/types/feature_flags/__init__.py +3 -0
- workos/types/feature_flags/feature_flag.py +12 -0
- workos/types/feature_flags/list_filters.py +5 -0
- workos/types/fga/__init__.py +5 -0
- workos/types/fga/authorization_resource_types.py +9 -0
- workos/types/fga/authorization_resources.py +10 -0
- workos/types/fga/check.py +51 -0
- workos/types/fga/list_filters.py +24 -0
- workos/types/fga/warnings.py +33 -0
- workos/types/fga/warrant.py +49 -0
- workos/types/list_resource.py +198 -0
- workos/types/metadata.py +4 -0
- workos/types/mfa/__init__.py +5 -0
- workos/types/mfa/authentication_challenge.py +14 -0
- workos/types/mfa/authentication_challenge_verification_response.py +9 -0
- workos/types/mfa/authentication_factor.py +70 -0
- workos/types/mfa/authentication_factor_totp_and_challenge_response.py +10 -0
- workos/types/mfa/enroll_authentication_factor_type.py +8 -0
- workos/types/organization_domains/__init__.py +1 -0
- workos/types/organization_domains/organization_domain.py +18 -0
- workos/types/organizations/__init__.py +6 -0
- workos/types/organizations/domain_data_input.py +7 -0
- workos/types/organizations/list_filters.py +6 -0
- workos/types/organizations/organization.py +13 -0
- workos/types/organizations/organization_common.py +12 -0
- workos/types/passwordless/__init__.py +2 -0
- workos/types/passwordless/passwordless_session.py +12 -0
- workos/types/passwordless/passwordless_session_type.py +3 -0
- workos/types/pipes/__init__.py +6 -0
- workos/types/pipes/pipes.py +34 -0
- workos/types/portal/__init__.py +2 -0
- workos/types/portal/portal_link.py +7 -0
- workos/types/portal/portal_link_intent.py +11 -0
- workos/types/portal/portal_link_intent_options.py +9 -0
- workos/types/roles/__init__.py +0 -0
- workos/types/roles/role.py +27 -0
- workos/types/sso/__init__.py +4 -0
- workos/types/sso/connection.py +70 -0
- workos/types/sso/connection_domain.py +8 -0
- workos/types/sso/profile.py +35 -0
- workos/types/sso/sso_provider_type.py +10 -0
- workos/types/user_management/__init__.py +12 -0
- workos/types/user_management/authenticate_with_common.py +66 -0
- workos/types/user_management/authentication_response.py +53 -0
- workos/types/user_management/email_verification.py +18 -0
- workos/types/user_management/impersonator.py +8 -0
- workos/types/user_management/invitation.py +26 -0
- workos/types/user_management/list_filters.py +29 -0
- workos/types/user_management/magic_auth.py +18 -0
- workos/types/user_management/oauth_tokens.py +21 -0
- workos/types/user_management/organization_membership.py +25 -0
- workos/types/user_management/password_hash_type.py +4 -0
- workos/types/user_management/password_reset.py +18 -0
- workos/types/user_management/screen_hint.py +3 -0
- workos/types/user_management/session.py +79 -0
- workos/types/user_management/user.py +22 -0
- workos/types/user_management/user_management_provider_type.py +11 -0
- workos/types/vault/__init__.py +2 -0
- workos/types/vault/key.py +25 -0
- workos/types/vault/object.py +38 -0
- workos/types/webhooks/__init__.py +0 -0
- workos/types/webhooks/webhook.py +330 -0
- workos/types/webhooks/webhook_model.py +14 -0
- workos/types/webhooks/webhook_payload.py +4 -0
- workos/types/widgets/__init__.py +2 -0
- workos/types/widgets/widget_scope.py +4 -0
- workos/types/widgets/widget_token_response.py +7 -0
- workos/types/workos_model.py +26 -0
- workos/typing/__init__.py +1 -0
- workos/typing/literals.py +32 -0
- workos/typing/sync_or_async.py +5 -0
- workos/typing/untyped_literal.py +37 -0
- workos/typing/webhooks.py +18 -0
- workos/user_management.py +2400 -0
- workos/utils/_base_http_client.py +252 -0
- workos/utils/crypto_provider.py +39 -0
- workos/utils/http_client.py +214 -0
- workos/utils/pagination_order.py +4 -0
- workos/utils/request_helper.py +27 -0
- workos/vault.py +544 -0
- workos/webhooks.py +96 -39
- workos/widgets.py +55 -0
- {workos-1.5.1.dist-info → workos-5.38.0.dist-info}/LICENSE +1 -1
- workos-5.38.0.dist-info/METADATA +107 -0
- workos-5.38.0.dist-info/RECORD +141 -0
- {workos-1.5.1.dist-info → workos-5.38.0.dist-info}/WHEEL +1 -1
- workos/audit_trail.py +0 -172
- workos/resources/base.py +0 -36
- workos/resources/event.py +0 -42
- workos/resources/event_action.py +0 -11
- workos/resources/sso.py +0 -53
- workos/utils/connection_types.py +0 -17
- workos/utils/request.py +0 -95
- workos/utils/validation.py +0 -45
- workos-1.5.1.dist-info/METADATA +0 -77
- workos-1.5.1.dist-info/RECORD +0 -25
- /workos/{resources/__init__.py → py.typed} +0 -0
- {workos-1.5.1.dist-info → workos-5.38.0.dist-info}/top_level.txt +0 -0
workos/organizations.py
CHANGED
|
@@ -1,31 +1,48 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
from typing import Optional, Protocol, Sequence
|
|
2
|
+
|
|
3
|
+
from workos.types.feature_flags import FeatureFlag
|
|
4
|
+
from workos.types.feature_flags.list_filters import FeatureFlagListFilters
|
|
5
|
+
from workos.types.metadata import Metadata
|
|
6
|
+
from workos.types.organizations.domain_data_input import DomainDataInput
|
|
7
|
+
from workos.types.organizations.list_filters import OrganizationListFilters
|
|
8
|
+
from workos.types.roles.role import RoleList
|
|
9
|
+
from workos.typing.sync_or_async import SyncOrAsync
|
|
10
|
+
from workos.utils.http_client import AsyncHTTPClient, SyncHTTPClient
|
|
11
|
+
from workos.utils.pagination_order import PaginationOrder
|
|
12
|
+
from workos.utils.request_helper import (
|
|
13
|
+
DEFAULT_LIST_RESPONSE_LIMIT,
|
|
4
14
|
REQUEST_METHOD_DELETE,
|
|
5
15
|
REQUEST_METHOD_GET,
|
|
6
16
|
REQUEST_METHOD_POST,
|
|
7
17
|
REQUEST_METHOD_PUT,
|
|
8
18
|
)
|
|
9
|
-
from workos.
|
|
19
|
+
from workos.types.organizations import Organization
|
|
20
|
+
from workos.types.list_resource import ListMetadata, ListPage, WorkOSListResource
|
|
10
21
|
|
|
11
22
|
ORGANIZATIONS_PATH = "organizations"
|
|
12
|
-
RESPONSE_LIMIT = 10
|
|
13
23
|
|
|
14
24
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
25
|
+
OrganizationsListResource = WorkOSListResource[
|
|
26
|
+
Organization, OrganizationListFilters, ListMetadata
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
FeatureFlagsListResource = WorkOSListResource[
|
|
30
|
+
FeatureFlag, FeatureFlagListFilters, ListMetadata
|
|
31
|
+
]
|
|
32
|
+
|
|
19
33
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if not getattr(self, "_request_helper", None):
|
|
23
|
-
self._request_helper = RequestHelper()
|
|
24
|
-
return self._request_helper
|
|
34
|
+
class OrganizationsModule(Protocol):
|
|
35
|
+
"""Offers methods through the WorkOS Organizations service."""
|
|
25
36
|
|
|
26
37
|
def list_organizations(
|
|
27
|
-
self,
|
|
28
|
-
|
|
38
|
+
self,
|
|
39
|
+
*,
|
|
40
|
+
domains: Optional[Sequence[str]] = None,
|
|
41
|
+
limit: int = DEFAULT_LIST_RESPONSE_LIMIT,
|
|
42
|
+
before: Optional[str] = None,
|
|
43
|
+
after: Optional[str] = None,
|
|
44
|
+
order: PaginationOrder = "desc",
|
|
45
|
+
) -> SyncOrAsync[OrganizationsListResource]:
|
|
29
46
|
"""Retrieve a list of organizations that have connections configured within your WorkOS dashboard.
|
|
30
47
|
|
|
31
48
|
Kwargs:
|
|
@@ -33,90 +50,403 @@ class Organizations(object):
|
|
|
33
50
|
limit (int): Maximum number of records to return. (Optional)
|
|
34
51
|
before (str): Pagination cursor to receive records before a provided Organization ID. (Optional)
|
|
35
52
|
after (str): Pagination cursor to receive records after a provided Organization ID. (Optional)
|
|
53
|
+
order (Literal["asc","desc"]): Sort records in either ascending or descending (default) order by created_at timestamp. (Optional)
|
|
36
54
|
|
|
37
55
|
Returns:
|
|
38
|
-
|
|
56
|
+
OrganizationsListResource: Organizations list response from WorkOS.
|
|
39
57
|
"""
|
|
40
|
-
|
|
41
|
-
|
|
58
|
+
...
|
|
59
|
+
|
|
60
|
+
def get_organization(self, organization_id: str) -> SyncOrAsync[Organization]:
|
|
61
|
+
"""Gets details for a single Organization
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
organization_id (str): Organization's unique identifier
|
|
65
|
+
Returns:
|
|
66
|
+
Organization: Organization response from WorkOS
|
|
67
|
+
"""
|
|
68
|
+
...
|
|
69
|
+
|
|
70
|
+
def get_organization_by_external_id(
|
|
71
|
+
self, external_id: str
|
|
72
|
+
) -> SyncOrAsync[Organization]:
|
|
73
|
+
"""Gets details for a single Organization by external id
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
external_id (str): Organization's external id
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Organization: Organization response from WorkOS
|
|
80
|
+
"""
|
|
81
|
+
...
|
|
82
|
+
|
|
83
|
+
def create_organization(
|
|
84
|
+
self,
|
|
85
|
+
*,
|
|
86
|
+
name: str,
|
|
87
|
+
domain_data: Optional[Sequence[DomainDataInput]] = None,
|
|
88
|
+
idempotency_key: Optional[str] = None,
|
|
89
|
+
external_id: Optional[str] = None,
|
|
90
|
+
metadata: Optional[Metadata] = None,
|
|
91
|
+
) -> SyncOrAsync[Organization]:
|
|
92
|
+
"""Create an organization
|
|
93
|
+
|
|
94
|
+
Kwargs:
|
|
95
|
+
name (str): A descriptive name for the organization. (Optional)
|
|
96
|
+
domain_data (Sequence[DomainDataInput]): List of domains that belong to the organization. (Optional)
|
|
97
|
+
idempotency_key (str): Key to guarantee idempotency across requests. (Optional)
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Organization: Updated Organization response from WorkOS.
|
|
101
|
+
"""
|
|
102
|
+
...
|
|
103
|
+
|
|
104
|
+
def update_organization(
|
|
105
|
+
self,
|
|
106
|
+
*,
|
|
107
|
+
organization_id: str,
|
|
108
|
+
name: Optional[str] = None,
|
|
109
|
+
domain_data: Optional[Sequence[DomainDataInput]] = None,
|
|
110
|
+
external_id: Optional[str] = None,
|
|
111
|
+
metadata: Optional[Metadata] = None,
|
|
112
|
+
) -> SyncOrAsync[Organization]:
|
|
113
|
+
"""Update an organization
|
|
114
|
+
|
|
115
|
+
Kwargs:
|
|
116
|
+
organization (str): Organization's unique identifier.
|
|
117
|
+
name (str): A descriptive name for the organization. (Optional)
|
|
118
|
+
domain_data (Sequence[DomainDataInput]): List of domains that belong to the organization. (Optional)
|
|
119
|
+
stripe_customer_id (str): The ID of the Stripe customer associated with the organization. (Optional)
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
Organization: Updated Organization response from WorkOS.
|
|
123
|
+
"""
|
|
124
|
+
...
|
|
125
|
+
|
|
126
|
+
def delete_organization(self, organization_id: str) -> SyncOrAsync[None]:
|
|
127
|
+
"""Deletes a single Organization
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
organization_id (str): Organization unique identifier
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
None
|
|
134
|
+
"""
|
|
135
|
+
...
|
|
136
|
+
|
|
137
|
+
def list_feature_flags(
|
|
138
|
+
self,
|
|
139
|
+
organization_id: str,
|
|
140
|
+
*,
|
|
141
|
+
limit: int = DEFAULT_LIST_RESPONSE_LIMIT,
|
|
142
|
+
before: Optional[str] = None,
|
|
143
|
+
after: Optional[str] = None,
|
|
144
|
+
order: PaginationOrder = "desc",
|
|
145
|
+
) -> SyncOrAsync[FeatureFlagsListResource]:
|
|
146
|
+
"""Retrieve a list of feature flags for an organization
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
organization_id (str): Organization's unique identifier
|
|
150
|
+
limit (int): Maximum number of records to return. (Optional)
|
|
151
|
+
before (str): Pagination cursor to receive records before a provided Feature Flag ID. (Optional)
|
|
152
|
+
after (str): Pagination cursor to receive records after a provided Feature Flag ID. (Optional)
|
|
153
|
+
order (Literal["asc","desc"]): Sort records in either ascending or descending (default) order by created_at timestamp. (Optional)
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
FeatureFlagsListResource: Feature flags list response from WorkOS.
|
|
157
|
+
"""
|
|
158
|
+
...
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class Organizations(OrganizationsModule):
|
|
162
|
+
_http_client: SyncHTTPClient
|
|
163
|
+
|
|
164
|
+
def __init__(self, http_client: SyncHTTPClient):
|
|
165
|
+
self._http_client = http_client
|
|
166
|
+
|
|
167
|
+
def list_organizations(
|
|
168
|
+
self,
|
|
169
|
+
*,
|
|
170
|
+
domains: Optional[Sequence[str]] = None,
|
|
171
|
+
limit: int = DEFAULT_LIST_RESPONSE_LIMIT,
|
|
172
|
+
before: Optional[str] = None,
|
|
173
|
+
after: Optional[str] = None,
|
|
174
|
+
order: PaginationOrder = "desc",
|
|
175
|
+
) -> OrganizationsListResource:
|
|
176
|
+
list_params: OrganizationListFilters = {
|
|
42
177
|
"limit": limit,
|
|
43
178
|
"before": before,
|
|
44
179
|
"after": after,
|
|
180
|
+
"order": order,
|
|
181
|
+
"domains": domains,
|
|
45
182
|
}
|
|
46
|
-
|
|
183
|
+
|
|
184
|
+
response = self._http_client.request(
|
|
47
185
|
ORGANIZATIONS_PATH,
|
|
48
186
|
method=REQUEST_METHOD_GET,
|
|
49
|
-
params=
|
|
50
|
-
token=workos.api_key,
|
|
187
|
+
params=list_params,
|
|
51
188
|
)
|
|
52
189
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"organizations/{
|
|
190
|
+
return WorkOSListResource[Organization, OrganizationListFilters, ListMetadata](
|
|
191
|
+
list_method=self.list_organizations,
|
|
192
|
+
list_args=list_params,
|
|
193
|
+
**ListPage[Organization](**response).model_dump(),
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
def get_organization(self, organization_id: str) -> Organization:
|
|
197
|
+
response = self._http_client.request(
|
|
198
|
+
f"organizations/{organization_id}", method=REQUEST_METHOD_GET
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
return Organization.model_validate(response)
|
|
202
|
+
|
|
203
|
+
def get_organization_by_external_id(self, external_id: str) -> Organization:
|
|
204
|
+
response = self._http_client.request(
|
|
205
|
+
"organizations/external_id/{external_id}".format(external_id=external_id),
|
|
62
206
|
method=REQUEST_METHOD_GET,
|
|
63
|
-
token=workos.api_key,
|
|
64
207
|
)
|
|
65
208
|
|
|
66
|
-
|
|
67
|
-
"""Create an organization
|
|
209
|
+
return Organization.model_validate(response)
|
|
68
210
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
211
|
+
def create_organization(
|
|
212
|
+
self,
|
|
213
|
+
*,
|
|
214
|
+
name: str,
|
|
215
|
+
domain_data: Optional[Sequence[DomainDataInput]] = None,
|
|
216
|
+
idempotency_key: Optional[str] = None,
|
|
217
|
+
external_id: Optional[str] = None,
|
|
218
|
+
metadata: Optional[Metadata] = None,
|
|
219
|
+
) -> Organization:
|
|
220
|
+
headers = {}
|
|
221
|
+
if idempotency_key:
|
|
222
|
+
headers["idempotency-key"] = idempotency_key
|
|
76
223
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
224
|
+
json = {
|
|
225
|
+
"name": name,
|
|
226
|
+
"domain_data": domain_data,
|
|
227
|
+
"idempotency_key": idempotency_key,
|
|
228
|
+
"external_id": external_id,
|
|
229
|
+
"metadata": metadata,
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
response = self._http_client.request(
|
|
81
233
|
ORGANIZATIONS_PATH,
|
|
82
234
|
method=REQUEST_METHOD_POST,
|
|
83
|
-
|
|
84
|
-
|
|
235
|
+
json=json,
|
|
236
|
+
headers=headers,
|
|
85
237
|
)
|
|
86
238
|
|
|
87
|
-
|
|
88
|
-
"""Update an organization
|
|
239
|
+
return Organization.model_validate(response)
|
|
89
240
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
241
|
+
def update_organization(
|
|
242
|
+
self,
|
|
243
|
+
*,
|
|
244
|
+
organization_id: str,
|
|
245
|
+
name: Optional[str] = None,
|
|
246
|
+
domain_data: Optional[Sequence[DomainDataInput]] = None,
|
|
247
|
+
stripe_customer_id: Optional[str] = None,
|
|
248
|
+
external_id: Optional[str] = None,
|
|
249
|
+
metadata: Optional[Metadata] = None,
|
|
250
|
+
) -> Organization:
|
|
251
|
+
json = {
|
|
252
|
+
"name": name,
|
|
253
|
+
"domain_data": domain_data,
|
|
254
|
+
"stripe_customer_id": stripe_customer_id,
|
|
255
|
+
"external_id": external_id,
|
|
256
|
+
"metadata": metadata,
|
|
257
|
+
}
|
|
97
258
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
259
|
+
response = self._http_client.request(
|
|
260
|
+
f"organizations/{organization_id}", method=REQUEST_METHOD_PUT, json=json
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
return Organization.model_validate(response)
|
|
264
|
+
|
|
265
|
+
def delete_organization(self, organization_id: str) -> None:
|
|
266
|
+
self._http_client.request(
|
|
267
|
+
f"organizations/{organization_id}",
|
|
268
|
+
method=REQUEST_METHOD_DELETE,
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
def list_organization_roles(self, organization_id: str) -> RoleList:
|
|
272
|
+
response = self._http_client.request(
|
|
273
|
+
f"organizations/{organization_id}/roles",
|
|
274
|
+
method=REQUEST_METHOD_GET,
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
return RoleList.model_validate(response)
|
|
278
|
+
|
|
279
|
+
def list_feature_flags(
|
|
280
|
+
self,
|
|
281
|
+
organization_id: str,
|
|
282
|
+
*,
|
|
283
|
+
limit: int = DEFAULT_LIST_RESPONSE_LIMIT,
|
|
284
|
+
before: Optional[str] = None,
|
|
285
|
+
after: Optional[str] = None,
|
|
286
|
+
order: PaginationOrder = "desc",
|
|
287
|
+
) -> FeatureFlagsListResource:
|
|
288
|
+
list_params: FeatureFlagListFilters = {
|
|
289
|
+
"limit": limit,
|
|
290
|
+
"before": before,
|
|
291
|
+
"after": after,
|
|
292
|
+
"order": order,
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
response = self._http_client.request(
|
|
296
|
+
f"organizations/{organization_id}/feature-flags",
|
|
297
|
+
method=REQUEST_METHOD_GET,
|
|
298
|
+
params=list_params,
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
return WorkOSListResource[FeatureFlag, FeatureFlagListFilters, ListMetadata](
|
|
302
|
+
list_method=self.list_feature_flags,
|
|
303
|
+
list_args=list_params,
|
|
304
|
+
**ListPage[FeatureFlag](**response).model_dump(),
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
class AsyncOrganizations(OrganizationsModule):
|
|
309
|
+
_http_client: AsyncHTTPClient
|
|
310
|
+
|
|
311
|
+
def __init__(self, http_client: AsyncHTTPClient):
|
|
312
|
+
self._http_client = http_client
|
|
313
|
+
|
|
314
|
+
async def list_organizations(
|
|
315
|
+
self,
|
|
316
|
+
*,
|
|
317
|
+
domains: Optional[Sequence[str]] = None,
|
|
318
|
+
limit: int = DEFAULT_LIST_RESPONSE_LIMIT,
|
|
319
|
+
before: Optional[str] = None,
|
|
320
|
+
after: Optional[str] = None,
|
|
321
|
+
order: PaginationOrder = "desc",
|
|
322
|
+
) -> OrganizationsListResource:
|
|
323
|
+
list_params: OrganizationListFilters = {
|
|
324
|
+
"limit": limit,
|
|
325
|
+
"before": before,
|
|
326
|
+
"after": after,
|
|
327
|
+
"order": order,
|
|
102
328
|
"domains": domains,
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
response = await self._http_client.request(
|
|
332
|
+
ORGANIZATIONS_PATH,
|
|
333
|
+
method=REQUEST_METHOD_GET,
|
|
334
|
+
params=list_params,
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
return WorkOSListResource[Organization, OrganizationListFilters, ListMetadata](
|
|
338
|
+
list_method=self.list_organizations,
|
|
339
|
+
list_args=list_params,
|
|
340
|
+
**ListPage[Organization](**response).model_dump(),
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
async def get_organization(self, organization_id: str) -> Organization:
|
|
344
|
+
response = await self._http_client.request(
|
|
345
|
+
f"organizations/{organization_id}", method=REQUEST_METHOD_GET
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
return Organization.model_validate(response)
|
|
349
|
+
|
|
350
|
+
async def get_organization_by_external_id(self, external_id: str) -> Organization:
|
|
351
|
+
response = await self._http_client.request(
|
|
352
|
+
"organizations/external_id/{external_id}".format(external_id=external_id),
|
|
353
|
+
method=REQUEST_METHOD_GET,
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
return Organization.model_validate(response)
|
|
357
|
+
|
|
358
|
+
async def create_organization(
|
|
359
|
+
self,
|
|
360
|
+
*,
|
|
361
|
+
name: str,
|
|
362
|
+
domain_data: Optional[Sequence[DomainDataInput]] = None,
|
|
363
|
+
idempotency_key: Optional[str] = None,
|
|
364
|
+
external_id: Optional[str] = None,
|
|
365
|
+
metadata: Optional[Metadata] = None,
|
|
366
|
+
) -> Organization:
|
|
367
|
+
headers = {}
|
|
368
|
+
if idempotency_key:
|
|
369
|
+
headers["idempotency-key"] = idempotency_key
|
|
370
|
+
|
|
371
|
+
json = {
|
|
103
372
|
"name": name,
|
|
373
|
+
"domain_data": domain_data,
|
|
374
|
+
"idempotency_key": idempotency_key,
|
|
375
|
+
"external_id": external_id,
|
|
376
|
+
"metadata": metadata,
|
|
104
377
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
378
|
+
|
|
379
|
+
response = await self._http_client.request(
|
|
380
|
+
ORGANIZATIONS_PATH,
|
|
381
|
+
method=REQUEST_METHOD_POST,
|
|
382
|
+
json=json,
|
|
383
|
+
headers=headers,
|
|
110
384
|
)
|
|
111
385
|
|
|
112
|
-
|
|
113
|
-
"""Deletes a single Organization
|
|
386
|
+
return Organization.model_validate(response)
|
|
114
387
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
388
|
+
async def update_organization(
|
|
389
|
+
self,
|
|
390
|
+
*,
|
|
391
|
+
organization_id: str,
|
|
392
|
+
name: Optional[str] = None,
|
|
393
|
+
domain_data: Optional[Sequence[DomainDataInput]] = None,
|
|
394
|
+
stripe_customer_id: Optional[str] = None,
|
|
395
|
+
external_id: Optional[str] = None,
|
|
396
|
+
metadata: Optional[Metadata] = None,
|
|
397
|
+
) -> Organization:
|
|
398
|
+
json = {
|
|
399
|
+
"name": name,
|
|
400
|
+
"domain_data": domain_data,
|
|
401
|
+
"stripe_customer_id": stripe_customer_id,
|
|
402
|
+
"external_id": external_id,
|
|
403
|
+
"metadata": metadata,
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
response = await self._http_client.request(
|
|
407
|
+
f"organizations/{organization_id}", method=REQUEST_METHOD_PUT, json=json
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
return Organization.model_validate(response)
|
|
411
|
+
|
|
412
|
+
async def delete_organization(self, organization_id: str) -> None:
|
|
413
|
+
await self._http_client.request(
|
|
414
|
+
f"organizations/{organization_id}",
|
|
120
415
|
method=REQUEST_METHOD_DELETE,
|
|
121
|
-
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
async def list_organization_roles(self, organization_id: str) -> RoleList:
|
|
419
|
+
response = await self._http_client.request(
|
|
420
|
+
f"organizations/{organization_id}/roles",
|
|
421
|
+
method=REQUEST_METHOD_GET,
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
return RoleList.model_validate(response)
|
|
425
|
+
|
|
426
|
+
async def list_feature_flags(
|
|
427
|
+
self,
|
|
428
|
+
organization_id: str,
|
|
429
|
+
*,
|
|
430
|
+
limit: int = DEFAULT_LIST_RESPONSE_LIMIT,
|
|
431
|
+
before: Optional[str] = None,
|
|
432
|
+
after: Optional[str] = None,
|
|
433
|
+
order: PaginationOrder = "desc",
|
|
434
|
+
) -> FeatureFlagsListResource:
|
|
435
|
+
list_params: FeatureFlagListFilters = {
|
|
436
|
+
"limit": limit,
|
|
437
|
+
"before": before,
|
|
438
|
+
"after": after,
|
|
439
|
+
"order": order,
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
response = await self._http_client.request(
|
|
443
|
+
f"organizations/{organization_id}/feature-flags",
|
|
444
|
+
method=REQUEST_METHOD_GET,
|
|
445
|
+
params=list_params,
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
return WorkOSListResource[FeatureFlag, FeatureFlagListFilters, ListMetadata](
|
|
449
|
+
list_method=self.list_feature_flags,
|
|
450
|
+
list_args=list_params,
|
|
451
|
+
**ListPage[FeatureFlag](**response).model_dump(),
|
|
122
452
|
)
|
workos/passwordless.py
CHANGED
|
@@ -1,54 +1,46 @@
|
|
|
1
|
-
import
|
|
2
|
-
from workos.utils.request import RequestHelper, REQUEST_METHOD_POST
|
|
3
|
-
from workos.utils.validation import PASSWORDLESS_MODULE, validate_settings
|
|
1
|
+
from typing import Literal, Optional, Protocol
|
|
4
2
|
|
|
3
|
+
from workos.types.passwordless.passwordless_session_type import PasswordlessSessionType
|
|
4
|
+
from workos.utils.http_client import SyncHTTPClient
|
|
5
|
+
from workos.utils.request_helper import REQUEST_METHOD_POST
|
|
6
|
+
from workos.types.passwordless.passwordless_session import PasswordlessSession
|
|
5
7
|
|
|
6
|
-
class Passwordless(object):
|
|
7
|
-
"""Offers methods through the WorkOS Passwordless service."""
|
|
8
|
-
|
|
9
|
-
@validate_settings(PASSWORDLESS_MODULE)
|
|
10
|
-
def __init__(self):
|
|
11
|
-
pass
|
|
12
8
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if not getattr(self, "_request_helper", None):
|
|
16
|
-
self._request_helper = RequestHelper()
|
|
17
|
-
return self._request_helper
|
|
9
|
+
class PasswordlessModule(Protocol):
|
|
10
|
+
"""Offers methods through the WorkOS Passwordless service."""
|
|
18
11
|
|
|
19
|
-
def create_session(
|
|
12
|
+
def create_session(
|
|
13
|
+
self,
|
|
14
|
+
*,
|
|
15
|
+
email: str,
|
|
16
|
+
type: PasswordlessSessionType,
|
|
17
|
+
redirect_uri: Optional[str] = None,
|
|
18
|
+
state: Optional[str] = None,
|
|
19
|
+
expires_in: Optional[int] = None,
|
|
20
|
+
) -> PasswordlessSession:
|
|
20
21
|
"""Create a Passwordless Session.
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
specific connection. Can be used to create a Passwordless Session
|
|
37
|
-
for a specific connection rather than using the domain from the email
|
|
38
|
-
to determine the Organization and Connection.
|
|
23
|
+
Kwargs:
|
|
24
|
+
email (str): The email of the user to authenticate.
|
|
25
|
+
type (PasswordlessSessionType): The type of Passwordless Session to
|
|
26
|
+
create. Currently, the only supported value is 'MagicLink'.
|
|
27
|
+
redirect_uri (str): Optional parameter to
|
|
28
|
+
specify the redirect endpoint which will handle the callback
|
|
29
|
+
from WorkOS. Defaults to the default Redirect URI in the
|
|
30
|
+
WorkOS dashboard. (Optional)
|
|
31
|
+
state (str): Optional parameter that the redirect
|
|
32
|
+
URI received from WorkOS will contain. The state parameter
|
|
33
|
+
can be used to encode arbitrary information to help
|
|
34
|
+
restore application state between redirects. (Optional)
|
|
35
|
+
expires_in (int): The number of seconds the Passwordless Session should live before expiring.
|
|
36
|
+
This value must be between 900 (15 minutes) and 86400 (24 hours), inclusive. (Optional)
|
|
39
37
|
|
|
40
38
|
Returns:
|
|
41
|
-
|
|
39
|
+
PasswordlessSession: A passwordless session object.
|
|
42
40
|
"""
|
|
41
|
+
...
|
|
43
42
|
|
|
44
|
-
|
|
45
|
-
"passwordless/sessions",
|
|
46
|
-
method=REQUEST_METHOD_POST,
|
|
47
|
-
params=session_options,
|
|
48
|
-
token=workos.api_key,
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
def send_session(self, session_id):
|
|
43
|
+
def send_session(self, session_id: str) -> Literal[True]:
|
|
52
44
|
"""Send a Passwordless Session via email.
|
|
53
45
|
|
|
54
46
|
Args:
|
|
@@ -58,10 +50,42 @@ class Passwordless(object):
|
|
|
58
50
|
Returns:
|
|
59
51
|
boolean: Returns True
|
|
60
52
|
"""
|
|
61
|
-
|
|
53
|
+
...
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class Passwordless(PasswordlessModule):
|
|
57
|
+
_http_client: SyncHTTPClient
|
|
58
|
+
|
|
59
|
+
def __init__(self, http_client: SyncHTTPClient):
|
|
60
|
+
self._http_client = http_client
|
|
61
|
+
|
|
62
|
+
def create_session(
|
|
63
|
+
self,
|
|
64
|
+
*,
|
|
65
|
+
email: str,
|
|
66
|
+
type: PasswordlessSessionType,
|
|
67
|
+
redirect_uri: Optional[str] = None,
|
|
68
|
+
state: Optional[str] = None,
|
|
69
|
+
expires_in: Optional[int] = None,
|
|
70
|
+
) -> PasswordlessSession:
|
|
71
|
+
json = {
|
|
72
|
+
"email": email,
|
|
73
|
+
"type": type,
|
|
74
|
+
"expires_in": expires_in,
|
|
75
|
+
"redirect_uri": redirect_uri,
|
|
76
|
+
"state": state,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
response = self._http_client.request(
|
|
80
|
+
"passwordless/sessions", method=REQUEST_METHOD_POST, json=json
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
return PasswordlessSession.model_validate(response)
|
|
84
|
+
|
|
85
|
+
def send_session(self, session_id: str) -> Literal[True]:
|
|
86
|
+
self._http_client.request(
|
|
62
87
|
"passwordless/sessions/{session_id}/send".format(session_id=session_id),
|
|
63
88
|
method=REQUEST_METHOD_POST,
|
|
64
|
-
token=workos.api_key,
|
|
65
89
|
)
|
|
66
90
|
|
|
67
91
|
return True
|