Skip to content

fix: accept the event and SSO queries workos-go v10 sends - #119

Merged
gjtorikian merged 8 commits into
workos:mainfrom
awartoft:fix/workos-go-v10-queries
Sep 22, 2026
Merged

gjtorikian merged 8 commits into
workos:mainfrom
awartoft:fix/workos-go-v10-queries

Conversation

@awartoft

Copy link
Copy Markdown
Contributor

Summary

workos-go v10.5.0 cannot drive the current emulator for the calls a directory-sync poller and a social login make. Confirmed by pointing that client at unmodified main (de4ccdc):

  • Events().List with events: ["user.created"] also returned organization.created. The SDK encodes the filter as repeated events= (url:"events"), and GET /events only read events[].
  • The same list ignored organization_id and a range_start an hour in the future. Both events from a two-organization seed came back, and so did an event created before the range.
  • SSO().GetAuthorizationURL with provider=GoogleOAuth returned 404 connection_not_found after a GoogleOAuth connection existed. Authorizing with that connection's id still returned 302 and a code.
  • After seeding a directory user into a group, Events().List for dsync.group.user_added returned dsync.user.created, dsync.group.created, dsync.activated, and organization.created.

This keeps Directory Sync read-only over HTTP. Membership events are emitted when a seeded or updated directory user's group set changes, including dsync.group.user_removed when the user leaves a group or is deleted. events[] still works. List order is unchanged: the v10 iterator sends order=desc itself when the caller omits it.

Test plan

  • bun test on the events, SSO, directory, and directory-seed specs
  • bun test full suite (1280 pass) before this branch
  • Reviewer: GET /events?events=user.created&events=user.updated returns only those types
  • Reviewer: GET /sso/authorize?provider=GoogleOAuth redirects when an active connection of that type exists

The Go SDK repeats events= rather than events[], and it filters with
range_start, range_end, and organization_id. Social login is
provider=GoogleOAuth. Seeding a directory user into a group never
emitted dsync.group.user_added or user_removed.
@greptile-apps

greptile-apps Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

The PR appears safe to merge; no actionable new defect remains, and all prior findings were manually resolved after the current code addressed their selection and scoping cases.

Summary

This PR expands WorkOS SDK compatibility across event filtering and organization scope, SSO provider selection, directory membership events, Connect application management, Client API tokens, and specification-derived identifier validation.

  • Records internal event organization scope without exposing it in public event payloads.
  • Supports repeated events= filters and additional event-list query constraints.
  • Resolves SSO provider requests while rejecting ambiguous tenant matches.
  • Emits directory group membership lifecycle events.
  • Adds Connect application and client-secret lifecycle endpoints plus Client API token issuance.
  • Aligns generated resource ID prefixes and response contracts with the OpenAPI specification.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  SDK[WorkOS SDK] --> Events[Events API]
  SDK --> SSO[SSO authorize]
  SDK --> Connect[Connect application APIs]
  Seed[Directory seed/update] --> Bus[Event bus]
  Bus --> Store[Stored events]
  Events --> Store
  SSO --> Connections[Organization-owned connections]
  Connect --> Applications[Applications and client secrets]
  Applications --> OAuth[OAuth token exchange]
Loading

Reviews (6) · Last reviewed commit: "Merge remote-tracking branch 'origin/mai..."

Comment thread src/workos/routes/events.ts Outdated
Comment thread src/workos/routes/sso.ts Outdated
The filter compared `data.organization_id`, so an organization-scoped
poller never saw `group.member_added`/`member_removed` (ids only),
`dsync.group.user_added`/`user_removed` (organization nested under the
user) or `organization.*` (the organization is the payload). Resolving
the scope when the event is recorded keeps it after the group or
directory it refers to is deleted; it stays off the wire because the
spec's Event has no such field.
`domain_hint` ran as a selector ahead of `provider`, so
`provider=MicrosoftOAuth&domain_hint=acme.com` 404ed unless some
connection claimed the domain, though the spec calls it a pre-fill
hint. And a provider matching connections in several organizations
took the first, minting the code under whichever tenant was created
first. The hint now narrows same-type connections; anything still
ambiguous is a 400 rather than a guess.
Comment thread src/workos/routes/sso.ts Outdated
Domains are case-insensitive, but connections keep theirs as written,
so a hint of `acme.com` failed to select a connection stored as
`Acme.com` and an otherwise resolvable provider login was refused as
ambiguous.
The provider path stopped caring about domain case; the selector that
takes a bare domain_hint still did, so the same hint resolved a
connection on one path and 404ed on the other.
Comment thread src/workos/routes/sso.ts Outdated
Nothing stops two organizations claiming the same domain, and the
hint-only selector took the first match, so a bare domain_hint could
mint the code under the wrong tenant, which is the guess the provider
path already declines to make. One rule for both selectors.
Reading `events=` alongside `events[]=` covered workos-go, -node and
-ruby, but turned the spec's own form — `style: form, explode: false`,
i.e. `events=a,b`, sent by workos-python, -kotlin, -elixir and -rust —
from an ignored filter into an empty result, since the joined value was
compared as one event name. Production parses the query with `qs` and
splits a scalar on commas, so it also takes workos-php's indexed
`events[0]=`. Normalize all four forms the way production does, and
pin each one in the spec.
@gjtorikian
gjtorikian merged commit 99db049 into workos:main Sep 22, 2026
9 checks passed
@gjtorikian

Copy link
Copy Markdown
Collaborator

thanks!

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