Skip to content

fix(oauth): preserve failed consent logout - #26

Merged
JOY (JOY) merged 1 commit into
devfrom
codex/beta-consent-logout
Aug 31, 2026
Merged

fix(oauth): preserve failed consent logout#26
JOY (JOY) merged 1 commit into
devfrom
codex/beta-consent-logout

Conversation

@JOY

@JOY JOY (JOY) commented Aug 31, 2026

Copy link
Copy Markdown

Problem

PR #25 preserved an OAuth consent 401, but the layout processed the logout header first and still redirected the browser to /, which Beta maps to /launches.

Change

Before every layout redirect side effect, preserve only a failed POST /oauth/authorize response with status 401. This applies even when a logout header is present. GET requests, other paths, other statuses, and normal logout behavior are unchanged.

Validation

  • pnpm exec jest --config tests/bootstrap.jest.cjs --runInBand tests/bootstrap-oauth-consent-error.spec.ts
  • pnpm --filter ./apps/frontend exec tsc --noEmit
  • git diff --check

Note

Medium Risk
Touches shared fetch/auth redirect logic for 401 and logout headers; scope is narrow but mistakes could affect sign-out or OAuth consent error handling.

Overview
Fixes a regression where a logout response header on a failed OAuth consent still triggered the layout fetch handler to clear session cookies and send users to / (often /launches on Beta), even when the consent UI should stay on the authorize page.

The global afterRequest hook now bails out first when the response is a 401 on POST /oauth/authorize, before auth/logout cookie handling or redirects. shouldPreserveOAuthConsentUnauthorized is tightened to that case only (POST, 401, authorize path, including absolute URLs). shouldHandleGlobalLogout centralizes when a logout header should force the normal global logout path鈥攊t runs only when a logout header is present and the response is not that preserved consent failure.

Tests cover method/path/status combinations and that consent POST + 401 + logout does not count as global logout, while other requests still do.

Reviewed by Cursor Bugbot for commit 9443ff2. Configure here.

@cursor

cursor Bot commented Aug 31, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_ec0d649e-99c2-437e-8237-7a6050b2bf56)

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the OAuth consent unauthorized handling and introduces a new helper function shouldHandleGlobalLogout to manage global logout logic based on URL, HTTP method, status, and logout headers. It also updates the layout context to use these helpers and adds corresponding unit tests. The review feedback suggests using optional chaining (options?.method) when accessing the method property of the options object in layout.context.tsx to prevent potential runtime TypeErrors if options is undefined.

Comment on lines +49 to +55
if (
shouldPreserveOAuthConsentUnauthorized(
url,
options.method,
response.status
)
) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using options.method directly can cause a runtime TypeError: Cannot read properties of undefined (reading 'method') if options is not provided (e.g., when a fetch request is initiated without an options object). Since options is potentially optional or undefined, it is safer to use optional chaining (options?.method).

Suggested change
if (
shouldPreserveOAuthConsentUnauthorized(
url,
options.method,
response.status
)
) {
if (
shouldPreserveOAuthConsentUnauthorized(
url,
options?.method,
response.status
)
) {

Comment on lines +67 to +75
if (
shouldHandleGlobalLogout(
url,
options.method,
response.status,
Boolean(logout)
) &&
!isSecured
) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using options.method directly can cause a runtime TypeError if options is undefined. Use optional chaining (options?.method) to safely handle cases where options is omitted.

Suggested change
if (
shouldHandleGlobalLogout(
url,
options.method,
response.status,
Boolean(logout)
) &&
!isSecured
) {
if (
shouldHandleGlobalLogout(
url,
options?.method,
response.status,
Boolean(logout)
) &&
!isSecured
) {

Comment on lines 104 to 112
if (
(response.status === 401 || response?.headers?.get('logout')) &&
!shouldPreserveOAuthConsentUnauthorized(
response.status === 401 ||
shouldHandleGlobalLogout(
url,
options.method,
response.status,
Boolean(response?.headers?.get('logout'))
Boolean(logout)
)
) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using options.method directly can cause a runtime TypeError if options is undefined. Use optional chaining (options?.method) to safely handle cases where options is omitted.

Suggested change
if (
(response.status === 401 || response?.headers?.get('logout')) &&
!shouldPreserveOAuthConsentUnauthorized(
response.status === 401 ||
shouldHandleGlobalLogout(
url,
options.method,
response.status,
Boolean(response?.headers?.get('logout'))
Boolean(logout)
)
) {
if (
response.status === 401 ||
shouldHandleGlobalLogout(
url,
options?.method,
response.status,
Boolean(logout)
)
) {

@JOY
JOY (JOY) merged commit b4c6179 into dev Aug 31, 2026
10 checks passed
@JOY
JOY (JOY) deleted the codex/beta-consent-logout branch August 31, 2026 15:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant