Skip to content

fix(auth): stop error callbacks crashing with NoMethodError in Rack middleware - #2910

Open
mroderick wants to merge 2 commits into
masterfrom
fix/omniauth-fail-returns-nil
Open

mroderick wants to merge 2 commits into
masterfrom
fix/omniauth-fail-returns-nil

Conversation

@mroderick

@mroderick mroderick commented Sep 22, 2026

Copy link
Copy Markdown
Collaborator

Provider error redirects from the auth app (invalid scope, PKCE required, state mismatch) reached the planner as a 500 (NoMethodError: undefined method '[]=' for nil, Rollbar item 714) instead of the intended redirect to /auth/failure.

Change

  • Return the failure response from fail! in callback_phase's error branch instead of discarding it with a bare return. The discarded response left the OmniAuth middleware returning nil, which Rack's TempfileReaper then crashed on.
  • In the same rescue path, re-raise exceptions raised by the app after successful auth (they are not auth failures) and return on_failure's response for auth failures.
  • Add regression specs covering both levels: the strategy must return a Rack response for provider error callbacks, and the full middleware stack must redirect to /auth/failure rather than raise.

Review notes

  • The behaviour change to note: exceptions raised by the controller during a successful callback previously got masked as "authentication error" redirects; they now propagate as normal 500s.
  • The redirect target and message stay unchanged (/auth/failure → flash + root); only the crash path is fixed.

CI failure follow-up

The first CI run failed one of the new specs. Cause: Capybara's Puma test server sets ENV['RACK_ENV'] ||= 'development' when a feature spec boots it mid-process, and omniauth's FailureEndpoint raises (instead of redirecting) whenever RACK_ENV is development. Specs running after a feature spec therefore saw raise-out behaviour. Fixed by pinning OmniAuth.config.failure_raise_out_environments = [] in the test environment, so failure handling is deterministic regardless of spec order.

The codebar OmniAuth strategy's callback_phase called fail! then bare
returned, discarding the failure response omniauth builds for
provider-side error redirects. The middleware returned nil, and Rack's
TempfileReaper raised "undefined method '[]=' for nil" when handling the
response, so any provider error redirect (invalid scope, PKCE required,
state mismatch) surfaced as a 500 instead of the /auth/failure redirect.

Return the fail! response from the error branch, and in the rescue path
re-raise app errors after successful auth while returning on_failure's
response for auth failures.
Puma's Capybara test server sets ENV['RACK_ENV'] ||= 'development' the
first time a feature spec boots it in-process. Omniauth's FailureEndpoint
then raises instead of redirecting for the rest of that rspec process, so
specs exercising omniauth failure paths behave differently depending on
whether a feature spec ran before them — the new omniauth request spec
failed on CI for exactly this reason.

Pin failure_raise_out_environments to empty in the test environment so
omniauth failure handling stays deterministic regardless of when Puma
mutates the process env.
@mroderick
mroderick marked this pull request as ready for review September 22, 2026 14:31

@olleolleolle olleolleolle left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks like a good idea! The specs read well.

This branch has not been deployed

No deployments
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.

2 participants