Skip to content

fix(auth): Emit spec-valid authentication_method#12

Merged
gjtorikian merged 2 commits into
mainfrom
fix/authentication-method-spec-valid
Jul 14, 2026
Merged

fix(auth): Emit spec-valid authentication_method#12
gjtorikian merged 2 commits into
mainfrom
fix/authentication-method-spec-valid

Conversation

@gjtorikian

@gjtorikian gjtorikian commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • The AuthenticateResponse.authentication_method enum is PascalCase and provider-specific — it has no bare OAuth, no MFA, and no EmailVerification. The emulator was returning its internal method categories verbatim, so those responses failed spec conformance.
  • Resolve the internal category to a spec-valid value via a new resolveResponseAuthMethod helper: an OAuth grant reports the user's explicitly configured oauth_provider, and an MFA/email-verification gate reports the primary method that initiated the flow.
  • When no truthful concrete method is known, omit the field (it is nullable in the SDKs) rather than fabricating a provider — the hosted authorize flow carries no provider info, so there is nothing honest to default to.
  • Add an internal oauth_provider field to seeded users (excluded from the user response) so OAuth logins can report a concrete, spec-valid provider like GoogleOAuth.
  • Document the oauth_provider seeding option in the README so the default omission reads as intended behavior rather than a bug.

Closes #11

The AuthenticateResponse authentication_method enum is PascalCase and
provider-specific — it has no bare 'OAuth', no 'MFA', and no
'EmailVerification'. The emulator was returning its internal method
categories verbatim, so those responses failed spec conformance.

Resolve the internal category to a spec-valid value instead: an OAuth
grant reports the user's explicitly configured oauth_provider, and an
MFA or email-verification gate reports the primary method that
initiated the flow. When no truthful concrete method is known, the
field is omitted (it is nullable in the SDKs) rather than fabricating
a provider — the hosted authorize flow carries no provider info, so
there is nothing honest to default to.
The spec-valid authentication_method fix made OAuth logins omit
the field by default, since the hosted authorize flow carries no
provider information. Document oauth_provider as the way to opt
into a concrete, spec-valid provider so the omission reads as
intended behavior rather than a bug.
@gjtorikian gjtorikian merged commit 3066f71 into main Jul 14, 2026
6 checks passed
@gjtorikian gjtorikian deleted the fix/authentication-method-spec-valid branch July 14, 2026 18:51
@greptile-apps

greptile-apps Bot commented Jul 14, 2026

Copy link
Copy Markdown

Greptile Summary

This PR makes authenticate responses emit spec-valid authentication_method values. The main changes are:

  • Adds an internal oauth_provider field for seeded users.
  • Resolves OAuth responses to the configured provider when present.
  • Omits authentication_method when no concrete provider or primary method is known.
  • Excludes oauth_provider from formatted user responses.
  • Updates tests and README guidance for the new response behavior.

Confidence Score: 4/5

This PR has one contained authenticate-response bug on refresh-token rotations.

Most changes are focused and covered by tests, but refresh-token responses can now lose the original concrete login method and return an omitted authentication_method instead.

src/workos/routes/auth.ts

T-Rex T-Rex Logs

What T-Rex did

  • I ran a focused Vitest route harness to reproduce the password login followed by a refresh token flow and observed an HTTP 200 response with authentication_method set to Password for the login step.
  • I re-used the same harness to perform a refresh flow and saw an HTTP 200 response where authentication_method was omitted, while the session sid remained unchanged and the auth_method stayed Password.
  • The repro test failed on the assertion that the refresh response should return authentication_method Password.
  • I reviewed the before-run artifact and the generated harness source to understand how the tests were constructed for the auth-response shape checks.
  • I reviewed the after-run log artifact to confirm the final assertions and observed authentication_method fields after the refresh flow, noting that the assertions passed.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
src/workos/routes/auth.ts Resolves response authentication_method through the new helper, but refresh-token rotations no longer preserve the original session authentication method.
src/workos/helpers.ts Excludes oauth_provider from formatted user payloads and adds resolveResponseAuthMethod for spec-valid authenticate response values.
src/workos/routes/auth.spec.ts Adds coverage for omitted OAuth provider, configured OAuth provider, and MFA primary-method reporting, but refresh-token method preservation is still untested.
src/workos/index.ts Adds oauth_provider to seed user typing and persists it during seed loading.
src/workos/entities.ts Adds an internal nullable oauth_provider field to WorkOSUser.
README.md Documents the new oauth_provider seed option and default omission behavior for OAuth authenticate responses.
src/e2e.spec.ts Updates the end-to-end OAuth login expectation to allow omitted authentication_method when no provider is configured.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Client
participant AuthRoute as authenticate handler
participant Store as WorkOS store
participant Helper as resolveResponseAuthMethod

Client->>AuthRoute: POST /user_management/authenticate grant
AuthRoute->>Store: Load user/session/grant context
alt OAuth grant
    AuthRoute->>Helper: "method=OAuth, oauthProvider=user.oauth_provider"
    Helper-->>AuthRoute: provider value or undefined
else MFA/email verification gate
    AuthRoute->>Helper: primary method when known
    Helper-->>AuthRoute: primary method or undefined
else Direct method
    AuthRoute->>Helper: Password/MagicAuth/SSO/etc.
    Helper-->>AuthRoute: same method
end
AuthRoute-->>Client: Authenticate response with spec-valid authentication_method or omitted
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 Client
participant AuthRoute as authenticate handler
participant Store as WorkOS store
participant Helper as resolveResponseAuthMethod

Client->>AuthRoute: POST /user_management/authenticate grant
AuthRoute->>Store: Load user/session/grant context
alt OAuth grant
    AuthRoute->>Helper: "method=OAuth, oauthProvider=user.oauth_provider"
    Helper-->>AuthRoute: provider value or undefined
else MFA/email verification gate
    AuthRoute->>Helper: primary method when known
    Helper-->>AuthRoute: primary method or undefined
else Direct method
    AuthRoute->>Helper: Password/MagicAuth/SSO/etc.
    Helper-->>AuthRoute: same method
end
AuthRoute-->>Client: Authenticate response with spec-valid authentication_method or omitted
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
src/workos/routes/auth.ts:602-604
**Refresh method lost**
For `refresh_token` grants this resolves from `authMethod`, which is hard-coded to `OAuth` on line 389 instead of the reused session's original method. A password login followed by refresh now returns no `authentication_method` unless the user has `oauth_provider`, even though the existing session at line 521 still records `auth_method: 'password'`, so refreshed responses no longer truthfully report `Password`.

Reviews (1): Last reviewed commit: "docs: Document oauth_provider for OAuth ..." | Re-trigger Greptile

Comment thread src/workos/routes/auth.ts
Comment on lines +602 to +604
authentication_method: resolveResponseAuthMethod(sessionAuthMethod ?? authMethod, {
oauthProvider: updatedUser.oauth_provider,
}),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Refresh method lost
For refresh_token grants this resolves from authMethod, which is hard-coded to OAuth on line 389 instead of the reused session's original method. A password login followed by refresh now returns no authentication_method unless the user has oauth_provider, even though the existing session at line 521 still records auth_method: 'password', so refreshed responses no longer truthfully report Password.

Artifacts

Repro: focused Vitest route harness for password login followed by refresh token authentication

  • Contains supporting evidence from the run (text/typescript; charset=utf-8).

Repro: verbose Vitest output showing HTTP statuses, response snippets, session auth_method, and failing assertion

  • Keeps the command output available without making the summary code-heavy.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/workos/routes/auth.ts
Line: 602-604

Comment:
**Refresh method lost**
For `refresh_token` grants this resolves from `authMethod`, which is hard-coded to `OAuth` on line 389 instead of the reused session's original method. A password login followed by refresh now returns no `authentication_method` unless the user has `oauth_provider`, even though the existing session at line 521 still records `auth_method: 'password'`, so refreshed responses no longer truthfully report `Password`.

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

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.

authentication_method: 'OAuth' breaks the Python SDK: spec issue or emulator issue?

1 participant