Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
* [#675](https://github.com/workos/workos-python/pull/675) fix(generated): regenerate from spec

**Fixes**
* **[organization_membership](https://workos.com/docs/reference/authkit/organization-membership)**:
* Added `roles` to organization membership models
2 changes: 1 addition & 1 deletion .last-synced-sha
Original file line number Diff line number Diff line change
@@ -1 +1 @@
b6a68da8bd60c1478e0a86ca97c75448677e8871
1a2f47b20f63f2c8f0eb56bbd2adb3b5947d693a
8 changes: 7 additions & 1 deletion .oagen-manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"version": 2,
"language": "python",
"generatedAt": "2026-06-17T20:55:36.392Z",
"generatedAt": "2026-06-25T13:50:58.519Z",
"files": [
"src/workos/_client.py",
"src/workos/admin_portal/__init__.py",
Expand Down Expand Up @@ -729,6 +729,7 @@
"tests/fixtures/audit_log_schema_target.json",
"tests/fixtures/audit_log_schema_target_input.json",
"tests/fixtures/audit_logs_retention.json",
"tests/fixtures/auth_method_mismatch_error.json",
"tests/fixtures/authenticate_response.json",
"tests/fixtures/authenticate_response_impersonator.json",
"tests/fixtures/authenticate_response_oauth_token.json",
Expand Down Expand Up @@ -1067,6 +1068,8 @@
"tests/fixtures/permission_updated_data.json",
"tests/fixtures/pipe_connected_account.json",
"tests/fixtures/pipes_connected_account_connected.json",
"tests/fixtures/pipes_connected_account_connection_failed.json",
"tests/fixtures/pipes_connected_account_connection_failed_data.json",
"tests/fixtures/pipes_connected_account_disconnected.json",
"tests/fixtures/pipes_connected_account_reauthorization_needed.json",
"tests/fixtures/portal_link_response.json",
Expand Down Expand Up @@ -1100,6 +1103,9 @@
"tests/fixtures/session_created.json",
"tests/fixtures/session_created_data.json",
"tests/fixtures/session_created_data_impersonator.json",
"tests/fixtures/session_reauthenticated.json",
"tests/fixtures/session_reauthenticated_data.json",
"tests/fixtures/session_reauthenticated_data_impersonator.json",
"tests/fixtures/session_revoked.json",
"tests/fixtures/session_revoked_data.json",
"tests/fixtures/session_revoked_data_impersonator.json",
Expand Down
18 changes: 12 additions & 6 deletions src/workos/common/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
AuthenticationSSOTimedOutDataError as AuthenticationSSOTimedOutDataError,
)
from .models import AuthenticationSSOTimedOutDataSSO as AuthenticationSSOTimedOutDataSSO
from .models import AuthMethodMismatchError as AuthMethodMismatchError
from .models import AuthorizationPermission as AuthorizationPermission
from .models import ConnectApplication as ConnectApplication
from .models import ConnectApplicationM2M as ConnectApplicationM2M
Expand Down Expand Up @@ -311,12 +312,6 @@
from .models import OrganizationDomainDataState as OrganizationDomainDataState
from .models import OrganizationDomainDeleted as OrganizationDomainDeleted
from .models import OrganizationDomainDeletedData as OrganizationDomainDeletedData
from .models import (
OrganizationDomainStandAloneState as OrganizationDomainStandAloneState,
)
from .models import (
OrganizationDomainStandAloneVerificationStrategy as OrganizationDomainStandAloneVerificationStrategy,
)
from .models import OrganizationDomainState as OrganizationDomainState
from .models import OrganizationDomainUpdated as OrganizationDomainUpdated
from .models import OrganizationDomainUpdatedData as OrganizationDomainUpdatedData
Expand Down Expand Up @@ -369,6 +364,12 @@
from .models import PermissionUpdatedData as PermissionUpdatedData
from .models import PipeConnectedAccount as PipeConnectedAccount
from .models import PipesConnectedAccountConnected as PipesConnectedAccountConnected
from .models import (
PipesConnectedAccountConnectionFailed as PipesConnectedAccountConnectionFailed,
)
from .models import (
PipesConnectedAccountConnectionFailedData as PipesConnectedAccountConnectionFailedData,
)
from .models import (
PipesConnectedAccountDisconnected as PipesConnectedAccountDisconnected,
)
Expand Down Expand Up @@ -398,6 +399,11 @@
from .models import SessionCreated as SessionCreated
from .models import SessionCreatedData as SessionCreatedData
from .models import SessionCreatedDataImpersonator as SessionCreatedDataImpersonator
from .models import SessionReauthenticated as SessionReauthenticated
from .models import SessionReauthenticatedData as SessionReauthenticatedData
from .models import (
SessionReauthenticatedDataImpersonator as SessionReauthenticatedDataImpersonator,
)
from .models import SessionRevoked as SessionRevoked
from .models import SessionRevokedData as SessionRevokedData
from .models import SessionRevokedDataImpersonator as SessionRevokedDataImpersonator
Expand Down
22 changes: 16 additions & 6 deletions src/workos/common/models/__init__.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 PR appears to be an incomplete code generation commit

The commit message is "chore(generated): shared regenerated files" which suggests this may be a partial commit of auto-generated output. The .oagen-manifest.json lists test fixture files for the new models but does not list corresponding src/workos/common/models/ source files for auth_method_mismatch_error, session_reauthenticated*, or pipes_connected_account_connection_failed*. This suggests the code generator intentionally did not produce these model files (perhaps they come from a different generation pass), yet the __init__.py re-exports were added prematurely. Similarly, the OrganizationDomainStandAlone re-export was removed from organization_domains/models/__init__.py but the consumer (_resource.py) was not updated — possibly because _resource.py is generated by a separate pass. If this PR is meant to land alongside another PR that provides the missing pieces, they should be coordinated to avoid a broken intermediate state on the main branch.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@
from .authentication_sso_timed_out_data_sso import (
AuthenticationSSOTimedOutDataSSO as AuthenticationSSOTimedOutDataSSO,
)
from .auth_method_mismatch_error import (
AuthMethodMismatchError as AuthMethodMismatchError,
)
Comment on lines +209 to +211

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0 Missing Generated Model Modules

These new re-exports import modules that are not included in the PR, starting with auth_method_mismatch_error.py and continuing with the new pipes and session models below. Any import of workos.common.models now fails at module load with ModuleNotFoundError, so the SDK and the new round-trip tests cannot load.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/workos/common/models/__init__.py
Line: 209-211

Comment:
**Missing Generated Model Modules**

These new re-exports import modules that are not included in the PR, starting with `auth_method_mismatch_error.py` and continuing with the new pipes and session models below. Any import of `workos.common.models` now fails at module load with `ModuleNotFoundError`, so the SDK and the new round-trip tests cannot load.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +209 to +211

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 New model classes are imported but their source files are missing, preventing the SDK from loading

Six new model classes are imported in the package init (src/workos/common/models/__init__.py:209-211) but the corresponding source files were never created, so importing the SDK at all will crash.

Impact: Any application that imports the workos package will fail immediately with a module-not-found error.

Missing source files for newly added imports

The PR adds imports in src/workos/common/models/__init__.py for:

  • AuthMethodMismatchError from .auth_method_mismatch_error (line 209-211)
  • PipesConnectedAccountConnectionFailed from .pipes_connected_account_connection_failed (line 557-559)
  • PipesConnectedAccountConnectionFailedData from .pipes_connected_account_connection_failed_data (line 560-562)
  • SessionReauthenticated from .session_reauthenticated (line 600)
  • SessionReauthenticatedData from .session_reauthenticated_data (line 601-603)
  • SessionReauthenticatedDataImpersonator from .session_reauthenticated_data_impersonator (line 604-606)

None of these .py files exist on disk. The .oagen-manifest.json lists test fixtures for these models but does not list source files under src/workos/common/models/. The test fixtures were created, and src/workos/common/__init__.py also re-exports these classes (lines 123, 367-372, 402-406), compounding the failure.

Since workos.common.models is imported transitively by virtually every part of the SDK, this makes the entire package non-functional.

Prompt for agents
The PR adds imports for 6 new model classes in src/workos/common/models/__init__.py (AuthMethodMismatchError, PipesConnectedAccountConnectionFailed, PipesConnectedAccountConnectionFailedData, SessionReauthenticated, SessionReauthenticatedData, SessionReauthenticatedDataImpersonator), but the corresponding Python source files under src/workos/common/models/ were never created. The code generator (oagen) appears to have generated the __init__.py changes, test fixtures, and manifest entries, but not the actual model source files. These files need to be generated and included in the PR. Each should follow the standard pattern: a @dataclass(slots=True) class with from_dict and to_dict methods, matching the structure shown in the test fixtures.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

from .authorization_permission import AuthorizationPermission as AuthorizationPermission
from .connect_application import ConnectApplication as ConnectApplication
from .connect_application_m2m import ConnectApplicationM2M as ConnectApplicationM2M
Expand Down Expand Up @@ -459,12 +462,6 @@
from .organization_domain_deleted_data import (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Removed Public Alias Exports

The standalone organization-domain state and verification-strategy alias modules still exist, but this change removes their public re-exports from workos.common.models and workos.common. Existing SDK users that import OrganizationDomainStandAloneState or OrganizationDomainStandAloneVerificationStrategy from those public package surfaces now get ImportError even though the underlying aliases were not removed.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/workos/common/models/__init__.py
Line: 462

Comment:
**Removed Public Alias Exports**

The standalone organization-domain state and verification-strategy alias modules still exist, but this change removes their public re-exports from `workos.common.models` and `workos.common`. Existing SDK users that import `OrganizationDomainStandAloneState` or `OrganizationDomainStandAloneVerificationStrategy` from those public package surfaces now get `ImportError` even though the underlying aliases were not removed.

How can I resolve this? If you propose a fix, please make it concise.

OrganizationDomainDeletedData as OrganizationDomainDeletedData,
)
from .organization_domain_stand_alone_state import (
OrganizationDomainStandAloneState as OrganizationDomainStandAloneState,
)
from .organization_domain_stand_alone_verification_strategy import (
OrganizationDomainStandAloneVerificationStrategy as OrganizationDomainStandAloneVerificationStrategy,
)
from .organization_domain_state import (
OrganizationDomainState as OrganizationDomainState,
)
Expand Down Expand Up @@ -557,6 +554,12 @@
from .pipes_connected_account_connected import (
PipesConnectedAccountConnected as PipesConnectedAccountConnected,
)
from .pipes_connected_account_connection_failed import (
PipesConnectedAccountConnectionFailed as PipesConnectedAccountConnectionFailed,
)
from .pipes_connected_account_connection_failed_data import (
PipesConnectedAccountConnectionFailedData as PipesConnectedAccountConnectionFailedData,
)
from .pipes_connected_account_disconnected import (
PipesConnectedAccountDisconnected as PipesConnectedAccountDisconnected,
)
Expand Down Expand Up @@ -594,6 +597,13 @@
from .session_created_data_impersonator import (
SessionCreatedDataImpersonator as SessionCreatedDataImpersonator,
)
from .session_reauthenticated import SessionReauthenticated as SessionReauthenticated
from .session_reauthenticated_data import (
SessionReauthenticatedData as SessionReauthenticatedData,
)
from .session_reauthenticated_data_impersonator import (
SessionReauthenticatedDataImpersonator as SessionReauthenticatedDataImpersonator,
)
from .session_revoked import SessionRevoked as SessionRevoked
from .session_revoked_data import SessionRevokedData as SessionRevokedData
from .session_revoked_data_impersonator import (
Expand Down
3 changes: 0 additions & 3 deletions src/workos/organization_domains/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,3 @@
from workos.common.models.organization_domain import (
OrganizationDomain as OrganizationDomain,
)
from .organization_domain_stand_alone import (
OrganizationDomainStandAlone as OrganizationDomainStandAlone,
)
Comment on lines -9 to -11

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Removing a model re-export breaks the organization domains feature entirely

The re-export of OrganizationDomainStandAlone is removed from the package init (src/workos/organization_domains/models/__init__.py:9-11), but the resource module still depends on it, so any use of the organization domains API will crash.

Impact: Calling get_organization_domain() or verify_organization_domain() raises an error, making the organization domains feature unusable.

Incomplete removal: re-export deleted but consumers not updated

The PR removes the re-export from src/workos/organization_domains/models/__init__.py (lines 9–11 on the old side), but src/workos/organization_domains/_resource.py:11 still does:

from .models import OrganizationDomainStandAlone

This import resolves against models/__init__.py, which no longer defines or re-exports OrganizationDomainStandAlone. The underlying file organization_domain_stand_alone.py still exists, but Python's from package import name only looks in the package's __init__.py, not in submodules.

The resource module uses OrganizationDomainStandAlone in get_organization_domain (_resource.py:63,84), verify_organization_domain (_resource.py:119,140), and their async counterparts (_resource.py:193,214,249,270).

Additionally, tests/test_organization_domains.py:10 imports it and multiple tests reference it (lines 44, 64, 183, 209).

Prompt for agents
The PR removes the OrganizationDomainStandAlone re-export from src/workos/organization_domains/models/__init__.py, but src/workos/organization_domains/_resource.py still imports OrganizationDomainStandAlone from .models (line 11) and uses it as the return type and model parameter in get_organization_domain and verify_organization_domain (both sync and async variants). Either restore the re-export in __init__.py, or update _resource.py to use OrganizationDomain directly (since OrganizationDomainStandAlone is just a TypeAlias for OrganizationDomain). Also update tests/test_organization_domains.py line 10 and its usages at lines 44, 64, 183, 209.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from datetime import datetime
from enum import Enum
from typing import cast
from typing import Any, Dict, Literal, Optional
from typing import Any, Dict, List, Literal, Optional
from workos._types import _raise_deserialize_error
from workos._types import _format_datetime, _parse_datetime

Expand Down Expand Up @@ -39,6 +39,8 @@ class OrganizationMembership:
"""An ISO 8601 timestamp."""
role: "SlimRole"
"""The primary role assigned to the user within the organization."""
roles: List["SlimRole"]
"""The list of roles assigned to the user within the organization."""
Comment on lines +42 to +43

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 New required roles field is a breaking change for existing API consumers

The roles field added to OrganizationMembership at src/workos/organization_membership/models/organization_membership.py:42 is non-optional and has no default value. In from_dict, it uses data["roles"] (line 67) rather than data.get("roles", []), meaning any API response that doesn't include a roles key will raise a KeyError (caught and re-raised as a deserialization error). This is consistent with how other required fields are handled, but it means that if users pin this SDK version while their WorkOS environment still returns the old response format (without roles), deserialization will fail. The existing test fixtures (organization_membership_created_data.json, organization_membership_updated_data.json) already include roles, suggesting the API already returns this field. Worth confirming that the API change is fully rolled out before releasing this SDK version.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

user: "User"
"""The user that belongs to the organization through this membership."""
organization_name: Optional[str] = None
Expand All @@ -60,6 +62,10 @@ def from_dict(cls, data: Dict[str, Any]) -> "OrganizationMembership":
created_at=_parse_datetime(data["created_at"]),
updated_at=_parse_datetime(data["updated_at"]),
role=SlimRole.from_dict(cast(Dict[str, Any], data["role"])),
roles=[
SlimRole.from_dict(cast(Dict[str, Any], item))
for item in cast(list[Any], data["roles"])
],
user=User.from_dict(cast(Dict[str, Any], data["user"])),
organization_name=data.get("organization_name"),
custom_attributes=data.get("custom_attributes"),
Expand All @@ -81,6 +87,7 @@ def to_dict(self) -> Dict[str, Any]:
result["created_at"] = _format_datetime(self.created_at)
result["updated_at"] = _format_datetime(self.updated_at)
result["role"] = self.role.to_dict()
result["roles"] = [item.to_dict() for item in self.roles]
result["user"] = self.user.to_dict()
if self.organization_name is not None:
result["organization_name"] = self.organization_name
Expand Down
4 changes: 4 additions & 0 deletions tests/fixtures/auth_method_mismatch_error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"code": "auth_method_mismatch",
"message": "This installation uses oauth authentication. Use the POST /:slug/token endpoint instead."
}
5 changes: 5 additions & 0 deletions tests/fixtures/list_user_organization_membership.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
"role": {
"slug": "admin"
},
"roles": [
{
"slug": "admin"
}
],
"user": {
"object": "user",
"id": "user_01E4ZCR3C56J083X43JQXF3JK5",
Expand Down
5 changes: 5 additions & 0 deletions tests/fixtures/organization_membership.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
"role": {
"slug": "admin"
},
"roles": [
{
"slug": "admin"
}
],
"user": {
"object": "user",
"id": "user_01E4ZCR3C56J083X43JQXF3JK5",
Expand Down
38 changes: 38 additions & 0 deletions tests/fixtures/pipes_connected_account_connection_failed.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"object": "event",
"id": "event_01EHZNVPK3SFK441A1RGBFSHRT",
"event": "pipes.connected_account.connection_failed",
"data": {
"object": "connection_failed",
"data_integration_id": "data_integration_01EHZNVPK3SFK441A1RGBFSHRT",
"provider_slug": "github",
"user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT",
"organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY",
"error_code": "authorization_code_exchange_error",
"error_reason": "The authorization code has expired.",
"provider_error": "access_denied",
"provider_error_description": "The user denied the authorization request.",
"created_at": "2026-01-15T12:00:00.000Z"
},
"created_at": "2026-01-15T12:00:00.000Z",
"context": {
"google_analytics_client_id": "GA1.2.1234567890.1234567890",
"google_analytics_sessions": [
{
"containerId": "GTM-ABCDEF",
"sessionId": "1234567890",
"sessionNumber": "1"
}
],
"ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY",
"client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY",
"actor": {
"id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY",
"source": "api",
"name": "Jane Doe"
},
"previous_attributes": {
"key": {}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"object": "connection_failed",
"data_integration_id": "data_integration_01EHZNVPK3SFK441A1RGBFSHRT",
"provider_slug": "github",
"user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT",
"organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY",
"error_code": "authorization_code_exchange_error",
"error_reason": "The authorization code has expired.",
"provider_error": "access_denied",
"provider_error_description": "The user denied the authorization request.",
"created_at": "2026-01-15T12:00:00.000Z"
}
44 changes: 44 additions & 0 deletions tests/fixtures/session_reauthenticated.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"object": "event",
"id": "event_01EHZNVPK3SFK441A1RGBFSHRT",
"event": "session.reauthenticated",
"data": {
"object": "session",
"id": "session_01H93ZY4F80QPBEZ1R5B2SHQG8",
"impersonator": {
"email": "admin@foocorp.com",
"reason": "Investigating an issue with the customer's account."
},
"ip_address": "198.51.100.42",
"organization_id": "org_01H945H0YD4F97JN9MATX7BYAG",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
"user_id": "user_01E4ZCR3C56J083X43JQXF3JK5",
"auth_method": "sso",
"status": "active",
"expires_at": "2026-01-15T12:00:00.000Z",
"ended_at": null,
"created_at": "2026-01-15T12:00:00.000Z",
"updated_at": "2026-01-15T12:00:00.000Z"
},
"created_at": "2026-01-15T12:00:00.000Z",
"context": {
"google_analytics_client_id": "GA1.2.1234567890.1234567890",
"google_analytics_sessions": [
{
"containerId": "GTM-ABCDEF",
"sessionId": "1234567890",
"sessionNumber": "1"
}
],
"ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY",
"client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY",
"actor": {
"id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY",
"source": "api",
"name": "Jane Doe"
},
"previous_attributes": {
"key": {}
}
}
}
18 changes: 18 additions & 0 deletions tests/fixtures/session_reauthenticated_data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"object": "session",
"id": "session_01H93ZY4F80QPBEZ1R5B2SHQG8",
"impersonator": {
"email": "admin@foocorp.com",
"reason": "Investigating an issue with the customer's account."
},
"ip_address": "198.51.100.42",
"organization_id": "org_01H945H0YD4F97JN9MATX7BYAG",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
"user_id": "user_01E4ZCR3C56J083X43JQXF3JK5",
"auth_method": "sso",
"status": "active",
"expires_at": "2026-01-15T12:00:00.000Z",
"ended_at": null,
"created_at": "2026-01-15T12:00:00.000Z",
"updated_at": "2026-01-15T12:00:00.000Z"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"email": "admin@foocorp.com",
"reason": "Investigating an issue with the customer's account."
}
5 changes: 5 additions & 0 deletions tests/fixtures/user_organization_membership.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
"role": {
"slug": "admin"
},
"roles": [
{
"slug": "admin"
}
],
"user": {
"object": "user",
"id": "user_01E4ZCR3C56J083X43JQXF3JK5",
Expand Down
Loading
Loading