Skip to content

feat: Add user API key methods - #1655

Merged
stanleyphu merged 3 commits into
mainfrom
devin/1783640650-user-api-keys
Jul 23, 2026
Merged

feat: Add user API key methods#1655
stanleyphu merged 3 commits into
mainfrom
devin/1783640650-user-api-keys

Conversation

@ethinallen

@ethinallen ethinallen commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Add userManagement.listUserApiKeys() and userManagement.createUserApiKey() for the user-scoped API key endpoints. The new types and serializers cover pagination, organization filtering, optional permissions and expiration, idempotency keys, and camel-cased user ownership metadata.

This complements #1650, which already added dual-owner ApiKey.owner types and camelized owner.organizationId during validation deserialization.

Documentation

Does this require changes to the WorkOS Docs? E.g. the API Reference or code snippets need updates.

[ ] Yes

If yes, link a related docs PR and add a docs maintainer as a reviewer. Their approval is required.

Link to Devin session: https://app.devin.ai/sessions/d37c887495594308a34bd8db9556dee9
Requested by: @ethinallen

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@ethinallen
ethinallen requested review from a team as code owners July 9, 2026 23:50
@ethinallen
ethinallen requested a review from alisherry July 9, 2026 23:50
@ethinallen ethinallen self-assigned this Jul 9, 2026
@devin-ai-integration

Copy link
Copy Markdown
Contributor
Original prompt from drew.emery

SYSTEM:
=== BEGIN THREAD HISTORY (in #docs-and-sdks) ===
<most_recent_message>
Drew Emery (U07PHF0U4P4): @Devin can you create a fix for the Node SDK that addresses:
• TypeScript types for ApiKey.owner only model organization-owned keys, not user-owned keys (owner.type is locked to 'organization', missing 'user' variant and organization_id field)
• deserializeApiKey doesn't camelize owner.organization_id to organizationId like other fields
• no SDK methods for user API key CRUD (POST/GET /user_management/users/{userId}/api_keys). Other SDKs (Python v7.0.0, .NET v4.0.0, PHP v6.0.0) have already shipped breaking changes for dual ownership model restructuring

[Slack unfurl — this is an automatic link preview, not a user message]
Quote of conversation (https://work-os.slack.com/archives/C0A4US8LCF9/p1783640070645839):
> From Bilal Shaikh
> Hey team! We're adopting the new user-scoped API keys (great addition!) and hit a gap in ``@workos-inc/node that we've confirmed on the latest release (10.7.0):

> 1. ApiKey.owner typings don't model user-owned keys. apiKeys.createValidation() returns owner: { type: "user", id: "user_…", organization_id: "org_…" } at runtime for user-scoped keys (verified against the live API), but the type is declared as { type: 'organization'; id: string }. TypeScript consumers can't branch on owner.type === "user" or read owner.organization_id without bypassing the type system.

> 2. owner.organization_id isn't camelized. deserializeApiKey camelizes every other field but passes owner through raw, so it's the lone snake_case field on the object. We've coded against the runtime shape for now — if the fix camelizes it to organizationId, that'll be a silent runtime break for anyone doing the same, so a heads-up in the release notes would be appreciated.

> 3. No SDK methods for user API key CRUD (POST/GET /user_management/users/{userId}/api_keys) — only the organization variants exist. We're calling the REST endpoin... (793 chars truncated...)

@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration devin-ai-integration Bot changed the title Add user API key methods feat: Add user API key methods Jul 9, 2026
@greptile-apps

greptile-apps Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds listUserApiKeys and createUserApiKey to UserManagement, covering pagination, organization filtering, optional permissions/expiration, and idempotency keys. All new types and serializers follow the established camelCase↔snake_case split used elsewhere in the SDK.

  • New listUserApiKeys(userId, options?) method returns an AutoPaginatable<UserApiKey> using the /user_management/users/:id/api_keys endpoint, with organizationId serialized to organization_id for the query string.
  • New createUserApiKey(userId, options, requestOptions?) method POSTs to the same endpoint and returns a UserApiKeyWithValue that includes the plaintext key value only on creation.
  • Tests verify response deserialization, filter serialization, and idempotency-key forwarding for both methods.

Confidence Score: 5/5

Safe to merge — the new methods are additive, well-tested, and follow the SDK's established serialization and pagination patterns exactly.

All serializers, deserializers, and interfaces are consistent with existing SDK patterns. Tests cover the full round-trip for both methods including edge cases like idempotency keys and pagination filters. No regressions to existing code paths are possible since both methods are purely additive.

No files require special attention.

Important Files Changed

Filename Overview
src/user-management/serializers/user-api-key.serializer.ts Deserializes the wire-format API key to the camelCase client model; hardcodes owner.type as 'user' instead of reading the value from the response
src/user-management/user-management.ts Adds listUserApiKeys and createUserApiKey methods; both follow established patterns for pagination, serialization, and idempotency but lack the userId guard present in getUserIdentities
src/user-management/interfaces/user-api-key.interface.ts Defines UserApiKey and SerializedUserApiKey with correct camelCase/snake_case split and owner shape
src/user-management/interfaces/list-user-api-keys-options.interface.ts Defines list options and serialized list options; consistent with the SerializedListSessionsOptions pattern of reusing PaginationOptions fields directly
src/user-management/interfaces/create-user-api-key-options.interface.ts Correctly separates user-facing options, serialized options, and request options with idempotency key support
src/user-management/serializers/user-api-key-with-value.serializer.ts Thin wrapper that spreads the base deserializer and appends value; straightforward and correct
src/user-management/user-management.spec.ts Tests cover happy-path response deserialization, pagination/filter serialization, and idempotency key forwarding for both new methods

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Caller
    participant UserManagement
    participant WorkOS API

    Caller->>UserManagement: listUserApiKeys(userId, options?)
    UserManagement->>UserManagement: serializeListUserApiKeysOptions(options)
    UserManagement->>WorkOS API: GET /user_management/users/:id/api_keys
    WorkOS API-->>UserManagement: { data: SerializedUserApiKey[], list_metadata }
    UserManagement->>UserManagement: deserializeUserApiKey (each item)
    UserManagement-->>Caller: "AutoPaginatable<UserApiKey>"

    Caller->>UserManagement: createUserApiKey(userId, options, requestOptions?)
    UserManagement->>UserManagement: serializeCreateUserApiKeyOptions(options)
    UserManagement->>WorkOS API: POST /user_management/users/:id/api_keys [Idempotency-Key header if provided]
    WorkOS API-->>UserManagement: SerializedUserApiKeyWithValue (includes value)
    UserManagement->>UserManagement: deserializeUserApiKeyWithValue
    UserManagement-->>Caller: UserApiKeyWithValue
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Caller
    participant UserManagement
    participant WorkOS API

    Caller->>UserManagement: listUserApiKeys(userId, options?)
    UserManagement->>UserManagement: serializeListUserApiKeysOptions(options)
    UserManagement->>WorkOS API: GET /user_management/users/:id/api_keys
    WorkOS API-->>UserManagement: { data: SerializedUserApiKey[], list_metadata }
    UserManagement->>UserManagement: deserializeUserApiKey (each item)
    UserManagement-->>Caller: "AutoPaginatable<UserApiKey>"

    Caller->>UserManagement: createUserApiKey(userId, options, requestOptions?)
    UserManagement->>UserManagement: serializeCreateUserApiKeyOptions(options)
    UserManagement->>WorkOS API: POST /user_management/users/:id/api_keys [Idempotency-Key header if provided]
    WorkOS API-->>UserManagement: SerializedUserApiKeyWithValue (includes value)
    UserManagement->>UserManagement: deserializeUserApiKeyWithValue
    UserManagement-->>Caller: UserApiKeyWithValue
Loading

Reviews (3): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile

Comment thread src/user-management/fixtures/create-user-api-key.json Outdated
ethinallen and others added 2 commits July 9, 2026 23:53
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@stanleyphu
stanleyphu merged commit 17e41e0 into main Jul 23, 2026
7 checks passed
@stanleyphu
stanleyphu deleted the devin/1783640650-user-api-keys branch July 23, 2026 18:19
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