workos 1.13.0__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 +105 -20
- workos/directory_sync.py +369 -146
- workos/events.py +111 -0
- workos/exceptions.py +53 -26
- workos/fga.py +649 -0
- workos/mfa.py +152 -116
- workos/organization_domains.py +179 -0
- workos/organizations.py +401 -86
- workos/passwordless.py +67 -43
- workos/pipes.py +93 -0
- workos/portal.py +51 -28
- workos/session.py +337 -0
- workos/sso.py +305 -149
- 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.13.0.dist-info → workos-5.38.0.dist-info}/LICENSE +1 -1
- {workos-1.13.0.dist-info → workos-5.38.0.dist-info}/METADATA +47 -22
- workos-5.38.0.dist-info/RECORD +141 -0
- {workos-1.13.0.dist-info → workos-5.38.0.dist-info}/WHEEL +1 -1
- workos/audit_trail.py +0 -179
- workos/resources/base.py +0 -36
- workos/resources/directory_sync.py +0 -28
- workos/resources/event.py +0 -42
- workos/resources/event_action.py +0 -11
- workos/resources/mfa.py +0 -32
- workos/resources/sso.py +0 -53
- workos/utils/connection_types.py +0 -35
- workos/utils/pagiantion_order.py +0 -6
- workos/utils/request.py +0 -100
- workos/utils/validation.py +0 -60
- workos-1.13.0.dist-info/RECORD +0 -29
- /workos/{resources/__init__.py → py.typed} +0 -0
- {workos-1.13.0.dist-info → workos-5.38.0.dist-info}/top_level.txt +0 -0
workos/sso.py
CHANGED
|
@@ -1,21 +1,27 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
from
|
|
4
|
-
from
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
-
from workos.utils.
|
|
8
|
-
from workos.
|
|
9
|
-
from workos.
|
|
10
|
-
|
|
11
|
-
from workos.utils.request import (
|
|
12
|
-
RequestHelper,
|
|
1
|
+
from typing import Optional, Protocol
|
|
2
|
+
from workos._client_configuration import ClientConfiguration
|
|
3
|
+
from workos.types.sso.connection import ConnectionType
|
|
4
|
+
from workos.types.sso.sso_provider_type import SsoProviderType
|
|
5
|
+
from workos.typing.sync_or_async import SyncOrAsync
|
|
6
|
+
from workos.utils.http_client import AsyncHTTPClient, SyncHTTPClient
|
|
7
|
+
from workos.utils.pagination_order import PaginationOrder
|
|
8
|
+
from workos.types.sso import ConnectionWithDomains, Profile, ProfileAndToken
|
|
9
|
+
from workos.utils.request_helper import (
|
|
10
|
+
DEFAULT_LIST_RESPONSE_LIMIT,
|
|
13
11
|
RESPONSE_TYPE_CODE,
|
|
14
12
|
REQUEST_METHOD_DELETE,
|
|
15
13
|
REQUEST_METHOD_GET,
|
|
16
14
|
REQUEST_METHOD_POST,
|
|
15
|
+
QueryParameters,
|
|
16
|
+
RequestHelper,
|
|
17
|
+
REQUEST_METHOD_PUT,
|
|
18
|
+
)
|
|
19
|
+
from workos.types.list_resource import (
|
|
20
|
+
ListArgs,
|
|
21
|
+
ListMetadata,
|
|
22
|
+
ListPage,
|
|
23
|
+
WorkOSListResource,
|
|
17
24
|
)
|
|
18
|
-
from workos.utils.validation import SSO_MODULE, validate_settings
|
|
19
25
|
|
|
20
26
|
AUTHORIZATION_PATH = "sso/authorize"
|
|
21
27
|
TOKEN_PATH = "sso/token"
|
|
@@ -23,201 +29,229 @@ PROFILE_PATH = "sso/profile"
|
|
|
23
29
|
|
|
24
30
|
OAUTH_GRANT_TYPE = "authorization_code"
|
|
25
31
|
|
|
26
|
-
RESPONSE_LIMIT = 10
|
|
27
32
|
|
|
33
|
+
class ConnectionsListFilters(ListArgs, total=False):
|
|
34
|
+
connection_type: Optional[ConnectionType]
|
|
35
|
+
domain: Optional[str]
|
|
36
|
+
organization_id: Optional[str]
|
|
28
37
|
|
|
29
|
-
class SSO(object):
|
|
30
|
-
"""Offers methods to assist in authenticating through the WorkOS SSO service."""
|
|
31
38
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
ConnectionsListResource = WorkOSListResource[
|
|
40
|
+
ConnectionWithDomains, ConnectionsListFilters, ListMetadata
|
|
41
|
+
]
|
|
35
42
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
|
|
44
|
+
class SSOModule(Protocol):
|
|
45
|
+
"""Offers methods to assist in authenticating through the WorkOS SSO service."""
|
|
46
|
+
|
|
47
|
+
_client_configuration: ClientConfiguration
|
|
41
48
|
|
|
42
49
|
def get_authorization_url(
|
|
43
50
|
self,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
state=None,
|
|
49
|
-
provider=None,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
):
|
|
51
|
+
*,
|
|
52
|
+
redirect_uri: str,
|
|
53
|
+
domain_hint: Optional[str] = None,
|
|
54
|
+
login_hint: Optional[str] = None,
|
|
55
|
+
state: Optional[str] = None,
|
|
56
|
+
provider: Optional[SsoProviderType] = None,
|
|
57
|
+
connection_id: Optional[str] = None,
|
|
58
|
+
organization_id: Optional[str] = None,
|
|
59
|
+
) -> str:
|
|
53
60
|
"""Generate an OAuth 2.0 authorization URL.
|
|
54
61
|
|
|
55
62
|
The URL generated will redirect a User to the Identity Provider configured through
|
|
56
63
|
WorkOS.
|
|
57
64
|
|
|
65
|
+
This method is purposefully designed as synchronous as it does not make any HTTP requests.
|
|
66
|
+
|
|
58
67
|
Kwargs:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
state (str) - An encoded string passed to WorkOS that'd be preserved through the authentication workflow, passed
|
|
68
|
+
redirect_uri (str) : A valid redirect URI, as specified on WorkOS
|
|
69
|
+
state (str) : An encoded string passed to WorkOS that'd be preserved through the authentication workflow, passed
|
|
62
70
|
back as a query parameter
|
|
63
|
-
provider (
|
|
64
|
-
|
|
65
|
-
|
|
71
|
+
provider (SSOProviderType) : Authentication service provider descriptor
|
|
72
|
+
connection_id (string) : Unique identifier for a WorkOS Connection
|
|
73
|
+
organization_id (string) : Unique identifier for a WorkOS Organization
|
|
66
74
|
|
|
67
75
|
Returns:
|
|
68
76
|
str: URL to redirect a User to to begin the OAuth workflow with WorkOS
|
|
69
77
|
"""
|
|
70
|
-
params = {
|
|
71
|
-
"client_id":
|
|
78
|
+
params: QueryParameters = {
|
|
79
|
+
"client_id": self._client_configuration.client_id,
|
|
72
80
|
"redirect_uri": redirect_uri,
|
|
73
81
|
"response_type": RESPONSE_TYPE_CODE,
|
|
74
82
|
}
|
|
75
83
|
|
|
76
|
-
if
|
|
77
|
-
domain is None
|
|
78
|
-
and provider is None
|
|
79
|
-
and connection is None
|
|
80
|
-
and organization is None
|
|
81
|
-
):
|
|
84
|
+
if connection_id is None and organization_id is None and provider is None:
|
|
82
85
|
raise ValueError(
|
|
83
|
-
"Incomplete arguments. Need to specify either a 'connection', 'organization',
|
|
86
|
+
"Incomplete arguments. Need to specify either a 'connection', 'organization', or 'provider'"
|
|
84
87
|
)
|
|
85
88
|
if provider is not None:
|
|
86
|
-
|
|
87
|
-
raise ValueError("'provider' must be of type ConnectionType")
|
|
88
|
-
params["provider"] = str(provider.value)
|
|
89
|
-
if domain is not None:
|
|
90
|
-
warn(
|
|
91
|
-
"The 'domain' parameter for 'get_authorization_url' is deprecated. Please use 'organization' instead.",
|
|
92
|
-
DeprecationWarning,
|
|
93
|
-
)
|
|
94
|
-
params["domain"] = domain
|
|
89
|
+
params["provider"] = provider
|
|
95
90
|
if domain_hint is not None:
|
|
96
91
|
params["domain_hint"] = domain_hint
|
|
97
92
|
if login_hint is not None:
|
|
98
93
|
params["login_hint"] = login_hint
|
|
99
|
-
if
|
|
100
|
-
params["connection"] =
|
|
101
|
-
if
|
|
102
|
-
params["organization"] =
|
|
94
|
+
if connection_id is not None:
|
|
95
|
+
params["connection"] = connection_id
|
|
96
|
+
if organization_id is not None:
|
|
97
|
+
params["organization"] = organization_id
|
|
103
98
|
|
|
104
99
|
if state is not None:
|
|
105
100
|
params["state"] = state
|
|
106
101
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
self.request_helper.generate_api_url(AUTHORIZATION_PATH),
|
|
113
|
-
params=params,
|
|
114
|
-
).prepare()
|
|
115
|
-
|
|
116
|
-
return prepared_request.url
|
|
102
|
+
return RequestHelper.build_url_with_query_params(
|
|
103
|
+
base_url=self._client_configuration.base_url,
|
|
104
|
+
path=AUTHORIZATION_PATH,
|
|
105
|
+
**params,
|
|
106
|
+
)
|
|
117
107
|
|
|
118
|
-
def get_profile(self,
|
|
108
|
+
def get_profile(self, access_token: str) -> SyncOrAsync[Profile]:
|
|
119
109
|
"""
|
|
120
110
|
Verify that SSO has been completed successfully and retrieve the identity of the user.
|
|
121
111
|
|
|
122
112
|
Args:
|
|
123
|
-
|
|
113
|
+
access_token (str): The token used to authenticate the API call
|
|
124
114
|
|
|
125
115
|
Returns:
|
|
126
|
-
|
|
116
|
+
Profile
|
|
127
117
|
"""
|
|
118
|
+
...
|
|
128
119
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
response = self.request_helper.request(
|
|
132
|
-
PROFILE_PATH, method=REQUEST_METHOD_GET, token=token
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
return WorkOSProfile.construct_from_response(response)
|
|
136
|
-
|
|
137
|
-
def get_profile_and_token(self, code):
|
|
120
|
+
def get_profile_and_token(self, code: str) -> SyncOrAsync[ProfileAndToken]:
|
|
138
121
|
"""Get the profile of an authenticated User
|
|
139
122
|
|
|
140
123
|
Once authenticated, using the code returned having followed the authorization URL,
|
|
141
124
|
get the WorkOS profile of the User.
|
|
142
125
|
|
|
143
126
|
Args:
|
|
144
|
-
code (str): Code returned by WorkOS on completion of OAuth 2.0 workflow
|
|
127
|
+
code (str): Code returned by WorkOS on completion of OAuth 2.0 workflow.
|
|
145
128
|
|
|
146
129
|
Returns:
|
|
147
|
-
|
|
130
|
+
ProfileAndToken: WorkOSProfileAndToken object representing the User.
|
|
148
131
|
"""
|
|
149
|
-
|
|
150
|
-
"client_id": workos.client_id,
|
|
151
|
-
"client_secret": workos.api_key,
|
|
152
|
-
"code": code,
|
|
153
|
-
"grant_type": OAUTH_GRANT_TYPE,
|
|
154
|
-
}
|
|
132
|
+
...
|
|
155
133
|
|
|
156
|
-
|
|
157
|
-
TOKEN_PATH, method=REQUEST_METHOD_POST, params=params
|
|
158
|
-
)
|
|
159
|
-
|
|
160
|
-
return WorkOSProfileAndToken.construct_from_response(response)
|
|
161
|
-
|
|
162
|
-
def get_connection(self, connection):
|
|
134
|
+
def get_connection(self, connection_id: str) -> SyncOrAsync[ConnectionWithDomains]:
|
|
163
135
|
"""Gets details for a single Connection
|
|
164
136
|
|
|
165
137
|
Args:
|
|
166
138
|
connection (str): Connection unique identifier
|
|
167
139
|
|
|
168
140
|
Returns:
|
|
169
|
-
|
|
141
|
+
ConnectionWithDomains: Connection response from WorkOS.
|
|
170
142
|
"""
|
|
171
|
-
|
|
172
|
-
"connections/{connection}".format(connection=connection),
|
|
173
|
-
method=REQUEST_METHOD_GET,
|
|
174
|
-
token=workos.api_key,
|
|
175
|
-
)
|
|
143
|
+
...
|
|
176
144
|
|
|
177
145
|
def list_connections(
|
|
178
146
|
self,
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
147
|
+
*,
|
|
148
|
+
connection_type: Optional[ConnectionType] = None,
|
|
149
|
+
domain: Optional[str] = None,
|
|
150
|
+
organization_id: Optional[str] = None,
|
|
151
|
+
limit: int = DEFAULT_LIST_RESPONSE_LIMIT,
|
|
152
|
+
before: Optional[str] = None,
|
|
153
|
+
after: Optional[str] = None,
|
|
154
|
+
order: PaginationOrder = "desc",
|
|
155
|
+
) -> SyncOrAsync[ConnectionsListResource]:
|
|
187
156
|
"""Gets details for existing Connections.
|
|
188
157
|
|
|
189
|
-
|
|
158
|
+
Kwargs:
|
|
190
159
|
connection_type (ConnectionType): Authentication service provider descriptor. (Optional)
|
|
191
160
|
domain (str): Domain of a Connection. (Optional)
|
|
192
161
|
limit (int): Maximum number of records to return. (Optional)
|
|
193
162
|
before (str): Pagination cursor to receive records before a provided Connection ID. (Optional)
|
|
194
163
|
after (str): Pagination cursor to receive records after a provided Connection ID. (Optional)
|
|
195
|
-
order (
|
|
164
|
+
order (Literal["asc","desc"]): Sort records in either ascending or descending (default) order by created_at timestamp. (Optional)
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
ConnectionsListResource: Connections response from WorkOS.
|
|
168
|
+
"""
|
|
169
|
+
...
|
|
196
170
|
|
|
171
|
+
def update_connection(
|
|
172
|
+
self,
|
|
173
|
+
*,
|
|
174
|
+
connection_id: str,
|
|
175
|
+
saml_options_signing_key: Optional[str] = None,
|
|
176
|
+
saml_options_signing_cert: Optional[str] = None,
|
|
177
|
+
) -> SyncOrAsync[ConnectionWithDomains]:
|
|
178
|
+
"""Updates a single connection
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
connection_id (str): Connection unique identifier
|
|
182
|
+
saml_options_signing_key (str): Signing key for the connection (Optional)
|
|
183
|
+
saml_options_signing_cert (str): Signing certificate for the connection (Optional)
|
|
197
184
|
Returns:
|
|
198
|
-
|
|
185
|
+
None
|
|
199
186
|
"""
|
|
187
|
+
...
|
|
188
|
+
|
|
189
|
+
def delete_connection(self, connection_id: str) -> SyncOrAsync[None]:
|
|
190
|
+
"""Deletes a single Connection
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
connection_id (str): Connection unique identifier
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
None
|
|
197
|
+
"""
|
|
198
|
+
...
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
class SSO(SSOModule):
|
|
202
|
+
_http_client: SyncHTTPClient
|
|
203
|
+
|
|
204
|
+
def __init__(
|
|
205
|
+
self, http_client: SyncHTTPClient, client_configuration: ClientConfiguration
|
|
206
|
+
):
|
|
207
|
+
self._client_configuration = client_configuration
|
|
208
|
+
self._http_client = http_client
|
|
209
|
+
|
|
210
|
+
def get_profile(self, access_token: str) -> Profile:
|
|
211
|
+
response = self._http_client.request(
|
|
212
|
+
PROFILE_PATH,
|
|
213
|
+
method=REQUEST_METHOD_GET,
|
|
214
|
+
headers={**self._http_client.auth_header_from_token(access_token)},
|
|
215
|
+
exclude_default_auth_headers=True,
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
return Profile.model_validate(response)
|
|
219
|
+
|
|
220
|
+
def get_profile_and_token(self, code: str) -> ProfileAndToken:
|
|
221
|
+
json = {
|
|
222
|
+
"client_id": self._http_client.client_id,
|
|
223
|
+
"client_secret": self._http_client.api_key,
|
|
224
|
+
"code": code,
|
|
225
|
+
"grant_type": OAUTH_GRANT_TYPE,
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
response = self._http_client.request(
|
|
229
|
+
TOKEN_PATH, method=REQUEST_METHOD_POST, json=json
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
return ProfileAndToken.model_validate(response)
|
|
200
233
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
234
|
+
def get_connection(self, connection_id: str) -> ConnectionWithDomains:
|
|
235
|
+
response = self._http_client.request(
|
|
236
|
+
f"connections/{connection_id}",
|
|
237
|
+
method=REQUEST_METHOD_GET,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
return ConnectionWithDomains.model_validate(response)
|
|
241
|
+
|
|
242
|
+
def list_connections(
|
|
243
|
+
self,
|
|
244
|
+
*,
|
|
245
|
+
connection_type: Optional[ConnectionType] = None,
|
|
246
|
+
domain: Optional[str] = None,
|
|
247
|
+
organization_id: Optional[str] = None,
|
|
248
|
+
limit: int = DEFAULT_LIST_RESPONSE_LIMIT,
|
|
249
|
+
before: Optional[str] = None,
|
|
250
|
+
after: Optional[str] = None,
|
|
251
|
+
order: PaginationOrder = "desc",
|
|
252
|
+
) -> ConnectionsListResource:
|
|
253
|
+
params: ConnectionsListFilters = {
|
|
254
|
+
"connection_type": connection_type,
|
|
221
255
|
"domain": domain,
|
|
222
256
|
"organization_id": organization_id,
|
|
223
257
|
"limit": limit,
|
|
@@ -225,25 +259,147 @@ class SSO(object):
|
|
|
225
259
|
"after": after,
|
|
226
260
|
"order": order,
|
|
227
261
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
raise ValueError("'order' must be of asc or desc order")
|
|
231
|
-
params["order"] = str(order.value)
|
|
232
|
-
return self.request_helper.request(
|
|
262
|
+
|
|
263
|
+
response = self._http_client.request(
|
|
233
264
|
"connections",
|
|
234
265
|
method=REQUEST_METHOD_GET,
|
|
235
266
|
params=params,
|
|
236
|
-
token=workos.api_key,
|
|
237
267
|
)
|
|
238
268
|
|
|
239
|
-
|
|
240
|
-
|
|
269
|
+
return WorkOSListResource[
|
|
270
|
+
ConnectionWithDomains, ConnectionsListFilters, ListMetadata
|
|
271
|
+
](
|
|
272
|
+
list_method=self.list_connections,
|
|
273
|
+
list_args=params,
|
|
274
|
+
**ListPage[ConnectionWithDomains](**response).model_dump(),
|
|
275
|
+
)
|
|
241
276
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
277
|
+
def update_connection(
|
|
278
|
+
self,
|
|
279
|
+
*,
|
|
280
|
+
connection_id: str,
|
|
281
|
+
saml_options_signing_key: Optional[str] = None,
|
|
282
|
+
saml_options_signing_cert: Optional[str] = None,
|
|
283
|
+
) -> ConnectionWithDomains:
|
|
284
|
+
json = {
|
|
285
|
+
"options": {
|
|
286
|
+
"signing_key": saml_options_signing_key,
|
|
287
|
+
"signing_cert": saml_options_signing_cert,
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
response = self._http_client.request(
|
|
292
|
+
f"connections/{connection_id}",
|
|
293
|
+
method=REQUEST_METHOD_PUT,
|
|
294
|
+
json=json,
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
return ConnectionWithDomains.model_validate(response)
|
|
298
|
+
|
|
299
|
+
def delete_connection(self, connection_id: str) -> None:
|
|
300
|
+
self._http_client.request(
|
|
301
|
+
f"connections/{connection_id}", method=REQUEST_METHOD_DELETE
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
class AsyncSSO(SSOModule):
|
|
306
|
+
_http_client: AsyncHTTPClient
|
|
307
|
+
|
|
308
|
+
def __init__(
|
|
309
|
+
self, http_client: AsyncHTTPClient, client_configuration: ClientConfiguration
|
|
310
|
+
):
|
|
311
|
+
self._client_configuration = client_configuration
|
|
312
|
+
self._http_client = http_client
|
|
313
|
+
|
|
314
|
+
async def get_profile(self, access_token: str) -> Profile:
|
|
315
|
+
response = await self._http_client.request(
|
|
316
|
+
PROFILE_PATH,
|
|
317
|
+
method=REQUEST_METHOD_GET,
|
|
318
|
+
headers={**self._http_client.auth_header_from_token(access_token)},
|
|
319
|
+
exclude_default_auth_headers=True,
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
return Profile.model_validate(response)
|
|
323
|
+
|
|
324
|
+
async def get_profile_and_token(self, code: str) -> ProfileAndToken:
|
|
325
|
+
json = {
|
|
326
|
+
"client_id": self._http_client.client_id,
|
|
327
|
+
"client_secret": self._http_client.api_key,
|
|
328
|
+
"code": code,
|
|
329
|
+
"grant_type": OAUTH_GRANT_TYPE,
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
response = await self._http_client.request(
|
|
333
|
+
TOKEN_PATH, method=REQUEST_METHOD_POST, json=json
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
return ProfileAndToken.model_validate(response)
|
|
337
|
+
|
|
338
|
+
async def get_connection(self, connection_id: str) -> ConnectionWithDomains:
|
|
339
|
+
response = await self._http_client.request(
|
|
340
|
+
f"connections/{connection_id}",
|
|
341
|
+
method=REQUEST_METHOD_GET,
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
return ConnectionWithDomains.model_validate(response)
|
|
345
|
+
|
|
346
|
+
async def list_connections(
|
|
347
|
+
self,
|
|
348
|
+
*,
|
|
349
|
+
connection_type: Optional[ConnectionType] = None,
|
|
350
|
+
domain: Optional[str] = None,
|
|
351
|
+
organization_id: Optional[str] = None,
|
|
352
|
+
limit: int = DEFAULT_LIST_RESPONSE_LIMIT,
|
|
353
|
+
before: Optional[str] = None,
|
|
354
|
+
after: Optional[str] = None,
|
|
355
|
+
order: PaginationOrder = "desc",
|
|
356
|
+
) -> ConnectionsListResource:
|
|
357
|
+
params: ConnectionsListFilters = {
|
|
358
|
+
"connection_type": connection_type,
|
|
359
|
+
"domain": domain,
|
|
360
|
+
"organization_id": organization_id,
|
|
361
|
+
"limit": limit,
|
|
362
|
+
"before": before,
|
|
363
|
+
"after": after,
|
|
364
|
+
"order": order,
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
response = await self._http_client.request(
|
|
368
|
+
"connections", method=REQUEST_METHOD_GET, params=params
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
return WorkOSListResource[
|
|
372
|
+
ConnectionWithDomains, ConnectionsListFilters, ListMetadata
|
|
373
|
+
](
|
|
374
|
+
list_method=self.list_connections,
|
|
375
|
+
list_args=params,
|
|
376
|
+
**ListPage[ConnectionWithDomains](**response).model_dump(),
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
async def update_connection(
|
|
380
|
+
self,
|
|
381
|
+
*,
|
|
382
|
+
connection_id: str,
|
|
383
|
+
saml_options_signing_key: Optional[str] = None,
|
|
384
|
+
saml_options_signing_cert: Optional[str] = None,
|
|
385
|
+
) -> ConnectionWithDomains:
|
|
386
|
+
json = {
|
|
387
|
+
"options": {
|
|
388
|
+
"signing_key": saml_options_signing_key,
|
|
389
|
+
"signing_cert": saml_options_signing_cert,
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
response = await self._http_client.request(
|
|
394
|
+
f"connections/{connection_id}",
|
|
395
|
+
method=REQUEST_METHOD_PUT,
|
|
396
|
+
json=json,
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
return ConnectionWithDomains.model_validate(response)
|
|
400
|
+
|
|
401
|
+
async def delete_connection(self, connection_id: str) -> None:
|
|
402
|
+
await self._http_client.request(
|
|
403
|
+
f"connections/{connection_id}",
|
|
247
404
|
method=REQUEST_METHOD_DELETE,
|
|
248
|
-
token=workos.api_key,
|
|
249
405
|
)
|
workos/types/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .api_keys import ApiKey as ApiKey # noqa: F401
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from typing import Literal, Optional, Sequence
|
|
2
|
+
|
|
3
|
+
from workos.types.workos_model import WorkOSModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ApiKeyOwner(WorkOSModel):
|
|
7
|
+
type: str
|
|
8
|
+
id: str
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ApiKey(WorkOSModel):
|
|
12
|
+
object: Literal["api_key"]
|
|
13
|
+
id: str
|
|
14
|
+
owner: ApiKeyOwner
|
|
15
|
+
name: str
|
|
16
|
+
obfuscated_value: str
|
|
17
|
+
last_used_at: Optional[str] = None
|
|
18
|
+
permissions: Sequence[str]
|
|
19
|
+
created_at: str
|
|
20
|
+
updated_at: str
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from typing_extensions import NotRequired, Sequence, TypedDict
|
|
2
|
+
|
|
3
|
+
from workos.types.audit_logs.audit_log_event_actor import AuditLogEventActor
|
|
4
|
+
from workos.types.audit_logs.audit_log_event_context import AuditLogEventContext
|
|
5
|
+
from workos.types.audit_logs.audit_log_metadata import AuditLogMetadata
|
|
6
|
+
from workos.types.audit_logs.audit_log_event_target import AuditLogEventTarget
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AuditLogEvent(TypedDict):
|
|
10
|
+
action: str
|
|
11
|
+
version: NotRequired[int]
|
|
12
|
+
occurred_at: str # ISO-8601 datetime of when an event occurred
|
|
13
|
+
actor: AuditLogEventActor
|
|
14
|
+
targets: Sequence[AuditLogEventTarget]
|
|
15
|
+
context: AuditLogEventContext
|
|
16
|
+
metadata: NotRequired[AuditLogMetadata]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from typing_extensions import NotRequired, TypedDict
|
|
2
|
+
|
|
3
|
+
from workos.types.audit_logs.audit_log_metadata import AuditLogMetadata
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AuditLogEventActor(TypedDict):
|
|
7
|
+
"""Describes the entity that generated the event."""
|
|
8
|
+
|
|
9
|
+
id: str
|
|
10
|
+
metadata: NotRequired[AuditLogMetadata]
|
|
11
|
+
name: NotRequired[str]
|
|
12
|
+
type: str
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from typing_extensions import NotRequired, TypedDict
|
|
2
|
+
|
|
3
|
+
from workos.types.audit_logs.audit_log_metadata import AuditLogMetadata
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AuditLogEventTarget(TypedDict):
|
|
7
|
+
"""Describes the entity that was targeted by the event."""
|
|
8
|
+
|
|
9
|
+
id: str
|
|
10
|
+
metadata: NotRequired[AuditLogMetadata]
|
|
11
|
+
name: NotRequired[str]
|
|
12
|
+
type: str
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from typing import Literal, Optional
|
|
2
|
+
|
|
3
|
+
from workos.types.workos_model import WorkOSModel
|
|
4
|
+
from workos.typing.literals import LiteralOrUntyped
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
AuditLogExportState = Literal["error", "pending", "ready"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AuditLogExport(WorkOSModel):
|
|
11
|
+
"""Representation of a WorkOS audit logs export."""
|
|
12
|
+
|
|
13
|
+
object: Literal["audit_log_export"]
|
|
14
|
+
id: str
|
|
15
|
+
created_at: str
|
|
16
|
+
updated_at: str
|
|
17
|
+
state: LiteralOrUntyped[AuditLogExportState]
|
|
18
|
+
url: Optional[str] = None
|