feat: Add Connect Applications and Client Secrets module#585
feat: Add Connect Applications and Client Secrets module#585gjtorikian merged 3 commits intoworkos:mainfrom
Conversation
Implement WorkOS Connect (M2M) endpoints for managing applications and client secrets via client.connect. Endpoints: - GET/POST /connect/applications (list, create) - GET/PUT/DELETE /connect/applications/:id (get, update, delete) - GET/POST /connect/applications/:id/client_secrets (list, create) - DELETE /connect/client_secrets/:id (delete) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Greptile SummaryThis PR adds a new Key changes:
Issues found:
Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Caller
participant client.connect
participant WorkOS API
Caller->>client.connect: create_application(name, application_type, ...)
client.connect->>WorkOS API: POST /connect/applications
WorkOS API-->>client.connect: ConnectApplication JSON
client.connect-->>Caller: ConnectApplication
Caller->>client.connect: get_application(application_id)
client.connect->>WorkOS API: GET /connect/applications/:id
WorkOS API-->>client.connect: ConnectApplication JSON
client.connect-->>Caller: ConnectApplication
Caller->>client.connect: update_application(application_id, name, ...)
client.connect->>WorkOS API: PUT /connect/applications/:id
WorkOS API-->>client.connect: ConnectApplication JSON
client.connect-->>Caller: ConnectApplication
Caller->>client.connect: list_applications(organization_id, ...)
client.connect->>WorkOS API: GET /connect/applications
WorkOS API-->>client.connect: List[ConnectApplication] + pagination
client.connect-->>Caller: ConnectApplicationsListResource
Caller->>client.connect: create_client_secret(application_id)
client.connect->>WorkOS API: POST /connect/applications/:id/client_secrets
WorkOS API-->>client.connect: ClientSecret JSON (with secret)
client.connect-->>Caller: ClientSecret
Caller->>client.connect: list_client_secrets(application_id, ...)
client.connect->>WorkOS API: GET /connect/applications/:id/client_secrets
WorkOS API-->>client.connect: List[ClientSecret] (no secret field)
client.connect-->>Caller: ClientSecretsListResource
Caller->>client.connect: delete_client_secret(client_secret_id)
client.connect->>WorkOS API: DELETE /connect/client_secrets/:id
WorkOS API-->>client.connect: 202 No Content
client.connect-->>Caller: None
Caller->>client.connect: delete_application(application_id)
client.connect->>WorkOS API: DELETE /connect/applications/:id
WorkOS API-->>client.connect: 202 No Content
client.connect-->>Caller: None
Last reviewed commit: 38e0333 |
| after: Optional[str] = None, | ||
| order: PaginationOrder = "desc", | ||
| ) -> ConnectApplicationsListResource: | ||
| list_params: ConnectApplicationListFilters = { | ||
| "organization_id": organization_id, | ||
| "limit": limit, |
There was a problem hiding this comment.
Unset optional fields sent as null may clear existing data
All optional fields default to None and are unconditionally included in the JSON payload, even when not supplied by the caller. The docstring for description explicitly states "Pass None to clear", which confirms the API does treat null as a clear-this-field instruction for at least that field.
This means a call like:
connect.update_application(application_id="app_01ABC", name="New Name")…sends {"name": "New Name", "description": null, "scopes": null, "redirect_uris": null} to the API. Depending on how the API handles null for scopes and redirect_uris, this could silently clear those fields even though the caller only intended to update the name.
Consider filtering out None values before sending — or at minimum document explicitly in the docstring which fields treat None as "clear" versus "no-op". A common pattern is:
json = {
k: v
for k, v in {
"name": name,
"description": description,
"scopes": scopes,
"redirect_uris": redirect_uris,
}.items()
if v is not None
}The same issue exists in the AsyncConnect.update_application implementation at lines 502–507.
|
|
||
| return WorkOSListResource[ | ||
| ClientSecret, ClientSecretListFilters, ListMetadata | ||
| ]( | ||
| list_method=partial(self.list_client_secrets, application_id), | ||
| list_args=list_params, | ||
| **ListPage[ClientSecret](**response).model_dump(), | ||
| ) | ||
|
|
||
| def delete_client_secret(self, client_secret_id: str) -> None: |
There was a problem hiding this comment.
None values for optional fields included in create_application payload
Optional fields (description, scopes, redirect_uris, uses_pkce, organization_id) are sent as null in the POST body even when not provided. Some REST APIs reject unknown or unexpected null values, or may exhibit unintended behaviour (e.g., failing schema validation for nullable-but-required-by-the-API arrays like scopes).
If the API gracefully ignores null for optional creation fields this is harmless, but it is safer to strip None values before sending:
json = {
k: v
for k, v in {
"name": name,
"application_type": application_type,
"is_first_party": is_first_party,
"description": description,
"scopes": scopes,
"redirect_uris": redirect_uris,
"uses_pkce": uses_pkce,
"organization_id": organization_id,
}.items()
if v is not None
}The same applies to AsyncConnect.create_application at lines 474–483.
| kwargs = { | ||
| "object": "connect_application", | ||
| "id": id, | ||
| "client_id": f"client_{id}", |
There was a problem hiding this comment.
application_type parameter typed as str instead of ApplicationType
The application_type parameter is typed as str rather than the ApplicationType = Literal["oauth", "m2m"] alias defined in connect_application.py. Using str loses type-safety and won't catch invalid values at the call site during static analysis.
| "client_id": f"client_{id}", | |
| def __init__(self, id: str, application_type: str = "m2m"): |
Consider importing and using ApplicationType:
from workos.types.connect.connect_application import ApplicationType
def __init__(self, id: str, application_type: ApplicationType = "m2m"):Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Pass None for response_dict and 202 for status_code in delete tests (previously 202 was incorrectly passed as response_dict) - Type application_type parameter as ApplicationType instead of str Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement WorkOS Connect (M2M) endpoints for managing applications and client secrets via client.connect.
Endpoints:
Description
Documentation
Does this require changes to the WorkOS Docs? E.g. the API Reference or code snippets need updates.
If yes, link a related docs PR and add a docs maintainer as a reviewer. Their approval is required.