Skip to content

feat(connect): Add Connect module#1597

Open
gjtorikian wants to merge 2 commits into
mainfrom
add-connect
Open

feat(connect): Add Connect module#1597
gjtorikian wants to merge 2 commits into
mainfrom
add-connect

Conversation

@gjtorikian
Copy link
Copy Markdown
Contributor

@gjtorikian gjtorikian commented May 20, 2026

Summary

  • Introduce a new Connect resource client on WorkOS for managing OAuth and M2M applications, application secrets, redirect URIs, user consent options, and the external auth login/consent flow.
  • Add generated interfaces, serializers, fixtures, and specs under src/connect/ from the latest oagen spec.
  • Export src/connect/interfaces from the package barrel so consumers can import the new types.

Test plan

  • npm test passes (unit + serializer specs)
  • npm run build succeeds with the new exports
  • workos.connect is reachable on the client and methods type-check from a consumer

Summary by CodeRabbit

  • New Features
    • Introduced WorkOS Connect API client with OAuth2 completion support
    • OAuth application management: create, list, retrieve, update, and delete operations
    • M2M (Machine-to-Machine) application creation and management
    • Application client secret management with creation and deletion capabilities
    • Pagination support for listing applications with organization filtering

Review Change Stack

@gjtorikian gjtorikian requested review from a team as code owners May 20, 2026 19:48
@gjtorikian gjtorikian requested a review from ericroberts May 20, 2026 19:48
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

📝 Walkthrough

Walkthrough

This PR adds a complete Connect API client module to the WorkOS SDK. It introduces TypeScript type contracts for OAuth and M2M applications, user identity management, and client secrets; implements bidirectional serializers for request/response transformation; provides a Connect API client class with full CRUD operations, pagination support, and OAuth2 completion; includes test fixtures and comprehensive Jest test coverage; and integrates the new module into the public SDK API and main WorkOS class.

Changes

Connect API Client Implementation

Layer / File(s) Summary
Connect Data Type Contracts
src/connect/interfaces/*
TypeScript interfaces and types define domain models (camelCase with Date) and wire response shapes (snake_case with ISO strings) for user objects, consent options, OAuth/M2M applications, redirect URIs, application secrets, and login requests. Includes union types combining OAuth and M2M variants.
Serialization Layer
src/connect/serializers/*
Bidirectional serializers transform between domain models and API wire formats, handling camelCase↔snake_case field mapping, Date↔ISO string conversion, and null-safety for optional timestamps and values across all Connect types and nested object structures.
Connect API Client Implementation
src/connect/connect.ts
Connect API client class provides methods for OAuth2 completion, application listing with pagination and organization filtering, application creation (OAuth/M2M variants via payload type switching), update/delete operations, and client secret management (list/create/delete). Uses serializers and shared fetch utilities.
Test Fixtures and Test Suite
src/connect/fixtures/*, src/connect/connect.spec.ts
JSON fixture files define request/response payloads for users, applications, secrets, and consent options. Jest test suite covers OAuth2 completion, application CRUD with request path and payload validation, client secret operations, and timestamp parsing into Date objects.
Public API Export and WorkOS Integration
src/index.ts, src/workos.ts, .oagen-manifest.json
Exposes Connect interfaces in public barrel export, adds readonly connect sub-client property to WorkOS main class, and updates generation manifest with new Connect module files.

Suggested reviewers

  • faroceann
  • imkesin
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding a new Connect module to the WorkOS SDK.
Description check ✅ Passed The pull request description is comprehensive and covers the key objectives, but does not follow the template structure requiring a Documentation section with checkbox.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-connect

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 20, 2026

Greptile Summary

Adds a new Connect resource client on the WorkOS class for managing OAuth and M2M applications, application secrets, redirect URIs, user consent options, and the external Standalone Connect auth flow. All types, serializers, fixtures, and specs are auto-generated from the oagen spec.

  • New Connect class (src/connect/connect.ts) wires completeOAuth2, listApplications (auto-paginatable), full CRUD for applications, and client-secret management onto the WorkOS instance.
  • Interfaces & serializers for every request/response shape are added under src/connect/interfaces/ and src/connect/serializers/, and the interfaces barrel is re-exported from src/index.ts.
  • Tests in connect.spec.ts cover the HTTP method, path, and representative response fields for each method.

Confidence Score: 3/5

Not ready to merge — updateApplication will silently clear existing optional fields on every partial update, and the pagination bug in listApplications (camelCase org filter dropped on page 2+) is still unresolved.

Two separate methods produce wrong wire payloads today: updateApplication always sends null for description, scopes, and redirect_uris when they are omitted, meaning a call like { name: 'rename' } would erase those fields on the server. Additionally, listApplications passes raw camelCase options to AutoPaginatable, so the organizationId filter is lost from the second page onward. Both issues affect core data paths for the new module.

src/connect/serializers/update-oauth-application.serializer.ts and src/connect/connect.ts (listApplications auto-pagination options) need the most attention before merge.

Important Files Changed

Filename Overview
src/connect/connect.ts Core Connect module; has the previously-flagged organizationId pagination bug and convenience-method serialization inconsistencies.
src/connect/serializers/update-oauth-application.serializer.ts Serializer for updateApplication; always emits null for unset optional fields, causing partial updates to unintentionally clear description, scopes, and redirect_uris.
src/connect/serializers/index.ts Serializers barrel; missing re-export for connect-application.serializer.ts (all other serializers are present).
src/connect/interfaces/index.ts Interfaces barrel; missing re-export for ListApplicationsOptions (previously flagged).
src/connect/connect.spec.ts Comprehensive unit tests covering all Connect methods; does not assert on the absence of null fields in the updateApplication body.
src/workos.ts Registers the new Connect instance as a readonly property on WorkOS; straightforward change.
src/index.ts Re-exports connect interfaces from the package barrel; correct placement.

Sequence Diagram

sequenceDiagram
    participant C as Consumer
    participant W as WorkOS.connect
    participant API as WorkOS API

    C->>W: "completeOAuth2({ externalAuthId, user })"
    W->>API: POST /authkit/oauth2/complete
    API-->>W: "{ redirect_uri }"
    W-->>C: ExternalAuthCompleteResponse

    C->>W: listApplications(options?)
    W->>API: GET /connect/applications
    API-->>W: paginated ConnectApplicationResponse[]
    W-->>C: "AutoPaginatable<ConnectApplication>"

    C->>W: "createApplication({ applicationType: 'oauth'|'m2m', ... })"
    W->>API: POST /connect/applications
    API-->>W: ConnectApplicationResponse
    W-->>C: ConnectApplication

    C->>W: updateApplication(id, payload)
    W->>API: PUT /connect/applications/:id
    Note over W,API: Sends null for unset optional fields
    API-->>W: ConnectApplicationResponse
    W-->>C: ConnectApplication

    C->>W: "createApplicationClientSecret(id, {})"
    W->>API: POST /connect/applications/:id/client_secrets
    API-->>W: NewConnectApplicationSecretResponse
    W-->>C: NewConnectApplicationSecret
Loading

Reviews (3): Last reviewed commit: "updates" | Re-trigger Greptile

Comment thread src/connect/interfaces/index.ts
Comment thread src/connect/connect.ts
Comment thread src/connect/connect.ts
Comment thread src/connect/connect.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (2)
src/connect/connect.ts (1)

210-228: ⚡ Quick win

Manual body construction bypasses serialization logic.

Similar to createOAuthApplication, this method manually builds the request body instead of using serializeCreateM2MApplication (imported at line 51). While M2M applications don't have nested objects requiring serialization like OAuth applications do, this is still inconsistent with:

  • The createApplication method (lines 139-163) which uses serializers
  • The updateApplication method (lines 257-269) which uses serializers
♻️ Recommended refactor to use the serializer
 async createM2MApplication(
   name: string,
   organizationId: string,
   description?: string | null,
   scopes?: string[] | null,
 ): Promise<ConnectApplication> {
-  const body: Record<string, unknown> = {
-    application_type: 'm2m',
-    name: name,
-    organization_id: organizationId,
-  };
-  if (description !== undefined) body.description = description;
-  if (scopes !== undefined) body.scopes = scopes;
-  const { data } = await this.workos.post<ConnectApplicationResponse>(
+  const payload: CreateM2MApplication = {
+    applicationType: 'm2m',
+    name,
+    organizationId,
+    ...(description !== undefined && { description }),
+    ...(scopes !== undefined && { scopes }),
+  };
+  const { data } = await this.workos.post<ConnectApplicationResponse, CreateM2MApplicationResponse>(
     '/connect/applications',
-    body,
+    serializeCreateM2MApplication(payload),
   );
   return deserializeConnectApplication(data);
 }
src/connect/serializers.spec.ts (1)

43-43: ⚡ Quick win

Type safety bypassed with as any cast.

The as any cast defeats TypeScript's type checking. While this may be intentional in generated code to handle minor fixture/interface mismatches, it means type errors in serializers won't be caught by these tests.

If oagen controls the generation, consider ensuring fixtures exactly match their corresponding interfaces to avoid needing as any.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a6438bd4-4c7e-48e1-b5b9-0e0b42b27e73

📥 Commits

Reviewing files that changed from the base of the PR and between 9ebc818 and cda0161.

📒 Files selected for processing (49)
  • .oagen-manifest.json
  • src/connect/connect.spec.ts
  • src/connect/connect.ts
  • src/connect/fixtures/application-credentials-list-item.json
  • src/connect/fixtures/connect-application.json
  • src/connect/fixtures/create-application-secret.json
  • src/connect/fixtures/create-m2m-application.json
  • src/connect/fixtures/create-oauth-application.json
  • src/connect/fixtures/external-auth-complete-response.json
  • src/connect/fixtures/list-connect-application.json
  • src/connect/fixtures/new-connect-application-secret.json
  • src/connect/fixtures/redirect-uri-input.json
  • src/connect/fixtures/update-oauth-application.json
  • src/connect/fixtures/user-consent-option-choice.json
  • src/connect/fixtures/user-consent-option.json
  • src/connect/fixtures/user-management-login-request.json
  • src/connect/fixtures/user-object.json
  • src/connect/interfaces/application-credentials-list-item.interface.ts
  • src/connect/interfaces/connect-application.interface.ts
  • src/connect/interfaces/create-application-secret.interface.ts
  • src/connect/interfaces/create-m2m-application.interface.ts
  • src/connect/interfaces/create-oauth-application.interface.ts
  • src/connect/interfaces/external-auth-complete-response.interface.ts
  • src/connect/interfaces/index.ts
  • src/connect/interfaces/list-applications-options.interface.ts
  • src/connect/interfaces/new-connect-application-secret.interface.ts
  • src/connect/interfaces/redirect-uri-input.interface.ts
  • src/connect/interfaces/update-oauth-application.interface.ts
  • src/connect/interfaces/user-consent-option-choice.interface.ts
  • src/connect/interfaces/user-consent-option.interface.ts
  • src/connect/interfaces/user-management-login-request.interface.ts
  • src/connect/interfaces/user-object.interface.ts
  • src/connect/serializers.spec.ts
  • src/connect/serializers/application-credentials-list-item.serializer.ts
  • src/connect/serializers/connect-application.serializer.ts
  • src/connect/serializers/create-application-secret.serializer.ts
  • src/connect/serializers/create-m2m-application.serializer.ts
  • src/connect/serializers/create-oauth-application.serializer.ts
  • src/connect/serializers/external-auth-complete-response.serializer.ts
  • src/connect/serializers/index.ts
  • src/connect/serializers/new-connect-application-secret.serializer.ts
  • src/connect/serializers/redirect-uri-input.serializer.ts
  • src/connect/serializers/update-oauth-application.serializer.ts
  • src/connect/serializers/user-consent-option-choice.serializer.ts
  • src/connect/serializers/user-consent-option.serializer.ts
  • src/connect/serializers/user-management-login-request.serializer.ts
  • src/connect/serializers/user-object.serializer.ts
  • src/index.ts
  • src/workos.ts

Comment thread src/connect/connect.ts
Comment thread src/connect/interfaces/application-credentials-list-item.interface.ts Outdated
Comment thread src/connect/interfaces/index.ts
Comment thread src/connect/interfaces/new-connect-application-secret.interface.ts Outdated
Comment thread src/connect/serializers.spec.ts Outdated
/** An ISO 8601 timestamp. */
updatedAt: Date;
/** The type of the application. */
applicationType?: 'm2m';
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.

The CreateM2MApplication and CreateOAuthApplication types look good, but this ConnectApplication type is a bit weird. I'd expect applicationType to be a discriminator between the two as the form a kind of union, but here it only lists m2m.

Seems like this modeling isn't quite right. Is there a way to get the generator to give us something better?

Comment thread src/connect/connect.ts
* @throws {UnprocessableEntityException} 422
*/
async createApplication(
payload: CreateOAuthApplication | CreateM2MApplication,
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.

Nice, this type of union of the different applications is more what I was imagining. 💯

Copy link
Copy Markdown
Contributor

@mthadley mthadley left a comment

Choose a reason for hiding this comment

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

@gjtorikian Overall, looks solid.

The only thing that looks off and that could be usability problem is this, so requesting changes until it can be addressed.

Comment on lines +9 to +19
export const serializeUpdateOAuthApplication = (
model: UpdateOAuthApplication,
): UpdateOAuthApplicationResponse => ({
name: model.name,
description: model.description ?? null,
scopes: model.scopes ?? null,
redirect_uris:
model.redirectUris != null
? model.redirectUris.map(serializeRedirectUriInput)
: null,
});
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 Partial update silently clears existing optional fields

description, scopes, and redirect_uris are serialized with ?? null or a falsy-null fallback, so when a caller passes only { name: 'New Name' }, the wire body becomes { name: "New Name", description: null, scopes: null, redirect_uris: null }. A typical REST API that receives explicit null on a PUT treats it as "clear this field", meaning existing description, scopes, and redirect URIs would be erased even though the caller never touched them.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/connect/connect.ts (1)

176-200: ⚠️ Potential issue | 🔴 Critical | ⚖️ Poor tradeoff

Critical: Still manually constructing request body instead of using serializer.

This method manually builds the wire-format request body (lines 185-194) with snake_case keys (application_type, is_first_party, redirect_uris) instead of using serializeCreateOAuthApplication, which is imported at line 50. This was flagged in a previous review as addressed in commits c82e4e8 to 4c21b9c, but the manual construction is still present in the current code.

The manual approach has a critical flaw: line 192 assigns redirectUris directly without calling serializeRedirectUriInput on each item, which transforms the default field from undefined to null per the wire format contract.

This breaks consistency with:

  • createApplication (line 150) — uses serializeCreateOAuthApplication
  • updateApplication (line 266) — uses serializeUpdateOAuthApplication
🔧 Refactor to use the serializer
   async createOAuthApplication(
     name: string,
     isFirstParty: boolean,
     description?: string | null,
     scopes?: string[] | null,
     redirectUris?: RedirectUriInput[] | null,
     usesPkce?: boolean | null,
     organizationId?: string | null,
   ): Promise<ConnectApplication> {
-    const body: Record<string, unknown> = {
-      application_type: 'oauth',
-      name: name,
-      is_first_party: isFirstParty,
-    };
-    if (description !== undefined) body.description = description;
-    if (scopes !== undefined) body.scopes = scopes;
-    if (redirectUris !== undefined) body.redirect_uris = redirectUris;
-    if (usesPkce !== undefined) body.uses_pkce = usesPkce;
-    if (organizationId !== undefined) body.organization_id = organizationId;
-    const { data } = await this.workos.post<ConnectApplicationResponse>(
+    const payload: CreateOAuthApplication = {
+      applicationType: 'oauth',
+      name,
+      isFirstParty,
+      ...(description !== undefined && { description }),
+      ...(scopes !== undefined && { scopes }),
+      ...(redirectUris !== undefined && { redirectUris }),
+      ...(usesPkce !== undefined && { usesPkce }),
+      ...(organizationId !== undefined && { organizationId }),
+    };
+    const { data } = await this.workos.post<
+      ConnectApplicationResponse,
+      CreateOAuthApplicationResponse
+    >(
       '/connect/applications',
-      body,
+      serializeCreateOAuthApplication(payload),
     );
     return deserializeConnectApplication(data);
   }
🧹 Nitpick comments (4)
src/connect/fixtures/external-auth-complete-response.json (1)

2-2: ⚡ Quick win

Use a clearly non-secret state fixture value.

This JWT-like sample triggers secret scanners and creates unnecessary security noise in CI. Prefer an obvious test placeholder (e.g., state=test_state_value).

♻️ Suggested fixture update
-  "redirect_uri": "https://your-authkit-domain.workos.com/oauth/authorize/complete?state=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdGF0ZSI6InJhbmRvbV9zdGF0ZV9zdHJpbmciLCJpYXQiOjE3NDI2MDQ4NTN9.abc123def456ghi789"
+  "redirect_uri": "https://your-authkit-domain.workos.com/oauth/authorize/complete?state=test_state_value"
src/connect/fixtures/new-connect-application-secret.json (1)

8-8: ⚡ Quick win

Replace the secret-looking literal with an explicit test sentinel.

This value looks like a real credential and can trip leak detection tooling. Use an obviously fake fixture value (e.g., not_a_real_secret_for_tests).

♻️ Suggested fixture update
-  "secret": "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz"
+  "secret": "not_a_real_secret_for_tests"
src/connect/connect.spec.ts (2)

54-56: ⚡ Quick win

Assert against fixture fields instead of duplicating sensitive-looking literals.

These hardcoded values duplicate fixture content and increase false-positive leak noise. Assert against imported fixture properties to keep a single source of truth.

♻️ Suggested test update
-      expect(result.redirectUri).toBe(
-        'https://your-authkit-domain.workos.com/oauth/authorize/complete?state=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdGF0ZSI6InJhbmRvbV9zdGF0ZV9zdHJpbmciLCJpYXQiOjE3NDI2MDQ4NTN9.abc123def456ghi789',
-      );
+      expect(result.redirectUri).toBe(
+        externalAuthCompleteResponseFixture.redirect_uri,
+      );
...
-      expect(result.secret).toBe(
-        'abc123def456ghi789jkl012mno345pqr678stu901vwx234yz',
-      );
+      expect(result.secret).toBe(newConnectApplicationSecretFixture.secret);

Also applies to: 191-193


71-74: ⚡ Quick win

Tighten listApplications assertions to validate deserialization, not just shape.

This test currently verifies non-empty output but not field mapping. Reuse the helper on the first item and assert listMetadata values from fixture to catch serializer regressions.

♻️ Suggested test update
       expect(fetchSearchParams()).toHaveProperty('order');
       expect(Array.isArray(data)).toBe(true);
-      expect(listMetadata).toBeDefined();
       expect(data.length).toBeGreaterThan(0);
+      expectConnectApplicationM2M(data[0]);
+      expect(listMetadata).toEqual({ before: null, after: null });

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5f2b581e-0f09-4e0b-975a-5346dbe38cf5

📥 Commits

Reviewing files that changed from the base of the PR and between 7bf0e10 and d58152d.

📒 Files selected for processing (50)
  • .oagen-manifest.json
  • src/connect/connect.spec.ts
  • src/connect/connect.ts
  • src/connect/fixtures/application-credentials-list-item.json
  • src/connect/fixtures/connect-application.json
  • src/connect/fixtures/create-application-secret.json
  • src/connect/fixtures/create-m2m-application.json
  • src/connect/fixtures/create-oauth-application.json
  • src/connect/fixtures/external-auth-complete-response.json
  • src/connect/fixtures/list-connect-application.json
  • src/connect/fixtures/new-connect-application-secret.json
  • src/connect/fixtures/redirect-uri-input.json
  • src/connect/fixtures/update-oauth-application.json
  • src/connect/fixtures/user-consent-option-choice.json
  • src/connect/fixtures/user-consent-option.json
  • src/connect/fixtures/user-management-login-request.json
  • src/connect/fixtures/user-object.json
  • src/connect/interfaces/application-credentials-list-item.interface.ts
  • src/connect/interfaces/connect-application-redirect-uri.interface.ts
  • src/connect/interfaces/connect-application.interface.ts
  • src/connect/interfaces/create-application-secret.interface.ts
  • src/connect/interfaces/create-m2m-application.interface.ts
  • src/connect/interfaces/create-oauth-application.interface.ts
  • src/connect/interfaces/external-auth-complete-response.interface.ts
  • src/connect/interfaces/index.ts
  • src/connect/interfaces/list-applications-options.interface.ts
  • src/connect/interfaces/new-connect-application-secret.interface.ts
  • src/connect/interfaces/redirect-uri-input.interface.ts
  • src/connect/interfaces/update-oauth-application.interface.ts
  • src/connect/interfaces/user-consent-option-choice.interface.ts
  • src/connect/interfaces/user-consent-option.interface.ts
  • src/connect/interfaces/user-management-login-request.interface.ts
  • src/connect/interfaces/user-object.interface.ts
  • src/connect/serializers/application-credentials-list-item.serializer.ts
  • src/connect/serializers/connect-application-redirect-uri.serializer.ts
  • src/connect/serializers/connect-application.serializer.ts
  • src/connect/serializers/create-application-secret.serializer.ts
  • src/connect/serializers/create-m2m-application.serializer.ts
  • src/connect/serializers/create-oauth-application.serializer.ts
  • src/connect/serializers/external-auth-complete-response.serializer.ts
  • src/connect/serializers/index.ts
  • src/connect/serializers/new-connect-application-secret.serializer.ts
  • src/connect/serializers/redirect-uri-input.serializer.ts
  • src/connect/serializers/update-oauth-application.serializer.ts
  • src/connect/serializers/user-consent-option-choice.serializer.ts
  • src/connect/serializers/user-consent-option.serializer.ts
  • src/connect/serializers/user-management-login-request.serializer.ts
  • src/connect/serializers/user-object.serializer.ts
  • src/index.ts
  • src/workos.ts
✅ Files skipped from review due to trivial changes (32)
  • src/connect/fixtures/create-m2m-application.json
  • src/connect/serializers/create-m2m-application.serializer.ts
  • src/connect/fixtures/create-oauth-application.json
  • src/connect/serializers/application-credentials-list-item.serializer.ts
  • src/connect/fixtures/user-object.json
  • src/connect/fixtures/update-oauth-application.json
  • src/connect/fixtures/redirect-uri-input.json
  • src/connect/interfaces/list-applications-options.interface.ts
  • src/connect/interfaces/connect-application-redirect-uri.interface.ts
  • src/connect/fixtures/user-consent-option-choice.json
  • src/connect/interfaces/create-m2m-application.interface.ts
  • src/connect/fixtures/application-credentials-list-item.json
  • src/connect/serializers/create-oauth-application.serializer.ts
  • src/connect/fixtures/create-application-secret.json
  • src/connect/serializers/user-management-login-request.serializer.ts
  • src/connect/interfaces/user-consent-option.interface.ts
  • src/connect/serializers/new-connect-application-secret.serializer.ts
  • src/connect/interfaces/user-consent-option-choice.interface.ts
  • src/connect/interfaces/user-object.interface.ts
  • src/connect/interfaces/update-oauth-application.interface.ts
  • src/connect/interfaces/redirect-uri-input.interface.ts
  • src/connect/serializers/connect-application.serializer.ts
  • src/connect/serializers/user-consent-option-choice.serializer.ts
  • src/connect/interfaces/user-management-login-request.interface.ts
  • src/connect/serializers/user-consent-option.serializer.ts
  • src/connect/interfaces/connect-application.interface.ts
  • src/connect/interfaces/external-auth-complete-response.interface.ts
  • src/connect/serializers/external-auth-complete-response.serializer.ts
  • .oagen-manifest.json
  • src/connect/fixtures/user-management-login-request.json
  • src/connect/interfaces/application-credentials-list-item.interface.ts
  • src/connect/interfaces/create-application-secret.interface.ts

Comment thread src/connect/connect.ts
Comment on lines +210 to +228
async createM2MApplication(
name: string,
organizationId: string,
description?: string | null,
scopes?: string[] | null,
): Promise<ConnectApplication> {
const body: Record<string, unknown> = {
application_type: 'm2m',
name: name,
organization_id: organizationId,
};
if (description !== undefined) body.description = description;
if (scopes !== undefined) body.scopes = scopes;
const { data } = await this.workos.post<ConnectApplicationResponse>(
'/connect/applications',
body,
);
return deserializeConnectApplication(data);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚖️ Poor tradeoff

Critical: Manually constructing request body instead of using serializer.

This method manually builds the wire-format request body (lines 216-222) instead of using serializeCreateM2MApplication (imported at line 51). This is the same critical issue present in createOAuthApplication and breaks consistency with createApplication (line 152), which correctly uses the serializer when applicationType is 'm2m'.

🔧 Refactor to use the serializer
   async createM2MApplication(
     name: string,
     organizationId: string,
     description?: string | null,
     scopes?: string[] | null,
   ): Promise<ConnectApplication> {
-    const body: Record<string, unknown> = {
-      application_type: 'm2m',
-      name: name,
-      organization_id: organizationId,
-    };
-    if (description !== undefined) body.description = description;
-    if (scopes !== undefined) body.scopes = scopes;
-    const { data } = await this.workos.post<ConnectApplicationResponse>(
+    const payload: CreateM2MApplication = {
+      applicationType: 'm2m',
+      name,
+      organizationId,
+      ...(description !== undefined && { description }),
+      ...(scopes !== undefined && { scopes }),
+    };
+    const { data } = await this.workos.post<
+      ConnectApplicationResponse,
+      CreateM2MApplicationResponse
+    >(
       '/connect/applications',
-      body,
+      serializeCreateM2MApplication(payload),
     );
     return deserializeConnectApplication(data);
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async createM2MApplication(
name: string,
organizationId: string,
description?: string | null,
scopes?: string[] | null,
): Promise<ConnectApplication> {
const body: Record<string, unknown> = {
application_type: 'm2m',
name: name,
organization_id: organizationId,
};
if (description !== undefined) body.description = description;
if (scopes !== undefined) body.scopes = scopes;
const { data } = await this.workos.post<ConnectApplicationResponse>(
'/connect/applications',
body,
);
return deserializeConnectApplication(data);
}
async createM2MApplication(
name: string,
organizationId: string,
description?: string | null,
scopes?: string[] | null,
): Promise<ConnectApplication> {
const payload: CreateM2MApplication = {
applicationType: 'm2m',
name,
organizationId,
...(description !== undefined && { description }),
...(scopes !== undefined && { scopes }),
};
const { data } = await this.workos.post<
ConnectApplicationResponse,
CreateM2MApplicationResponse
>(
'/connect/applications',
serializeCreateM2MApplication(payload),
);
return deserializeConnectApplication(data);
}

createdAt: Date;
/** An ISO 8601 timestamp. */
updatedAt: Date;
applicationType: 'oauth';
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.

hmm, looks like we are missing a "description" somewhere for applicationType. Maybe something to track down later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants