Skip to content

Map LoginController failures to specific HTTP errors#33

Merged
turegjorup merged 5 commits into
developfrom
feature/login-controller-http-errors
May 11, 2026
Merged

Map LoginController failures to specific HTTP errors#33
turegjorup merged 5 commits into
developfrom
feature/login-controller-http-errors

Conversation

@turegjorup
Copy link
Copy Markdown
Contributor

Summary

Previously, any failure during the OIDC authorization redirect (LoginController::login()) bubbled unhandled as a generic HTTP 500. Map to specific responses:

Cause Response
InvalidProviderException (unknown provider key) NotFoundHttpException (404)
HttpException / JsonException / CacheException (metadata fetch / cache failure) ServiceUnavailableHttpException (503)
Other ItkOpenIdConnectException subtypes (config-time errors like BadUrlException) unchanged — still bubble as 500, correct for "server-side config bug"

Original exception chained via previous so logs and error reporters retain the cause.

Backward compatibility

Additive only. The 500-bubbling behavior was never an explicit contract; consumers catching \Throwable keep working. Anything specifically catching ItkOpenIdConnectException from this controller would have been broken anyway (Symfony was rendering 500 before, not handing the exception back to caller code).

Test plan

  • task test — 50 tests pass (3 new: 1 happy path retained, 1 unknown-provider-404 case, 1 data-provided 503 case across HttpException/JsonException/CacheException)
  • task analyze:php — phpstan max level, no errors
  • task lint — clean (php-cs-fixer normalized one docblock)
  • task test:matrix — all 6 PHP × deps combinations green

🤖 Generated with Claude Code

Previously any failure during the OIDC authorization redirect bubbled
unhandled as a generic 500. Map to specific responses:

- InvalidProviderException        -> NotFoundHttpException (404)
- HttpException / JsonException /
  CacheException (metadata fetch)  -> ServiceUnavailableHttpException (503)

Cause chained via `previous`. Other ItkOpenIdConnectException subtypes
(config-time errors) still bubble as 500 — correctly indicates a
server-side configuration bug.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 8, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (73b94dd) to head (c3385ca).

Additional details and impacted files
@@             Coverage Diff             @@
##             develop       #33   +/-   ##
===========================================
  Coverage     100.00%   100.00%           
- Complexity        58        60    +2     
===========================================
  Files              9         9           
  Lines            274       278    +4     
===========================================
+ Hits             274       278    +4     
Flag Coverage Δ
unittests 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@turegjorup turegjorup self-assigned this May 8, 2026
@turegjorup turegjorup requested a review from jekuaitk May 8, 2026 09:42
Comment on lines +49 to +61
try {
$authUrl = $provider->getAuthorizationUrl([
'state' => $state,
'nonce' => $nonce,
'response_type' => 'code',
'scope' => 'openid email profile',
]);
} catch (HttpException|JsonException|CacheException $e) {
// Building the authorization URL fetches the IdP's discovery
// document. Surface upstream/transport failures as 503 with the
// cause chained, rather than an unhandled 500.
throw new ServiceUnavailableHttpException(null, sprintf('Cannot reach OIDC provider "%s"', $providerKey), $e);
}
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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

InvalidArgumentException maps to ServiceUnavailableHttpException. The rest are allowed to bubble up.


try {
$controller->login($this->createStub(Request::class), $this->createStub(SessionInterface::class), 'bogus');
$this->fail('Expected NotFoundHttpException');
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.

Suggested change
$this->fail('Expected NotFoundHttpException');


try {
$controller->login($this->createStub(Request::class), $this->createStub(SessionInterface::class), 'test');
$this->fail('Expected ServiceUnavailableHttpException');
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.

Suggested change
$this->fail('Expected ServiceUnavailableHttpException');

Comment on lines +35 to +39
try {
$provider = $this->providerManager->getProvider($providerKey);
} catch (InvalidProviderException $e) {
throw new NotFoundHttpException(sprintf('Unknown OIDC provider "%s"', $providerKey), $e);
}
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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@throws updated.

turegjorup and others added 3 commits May 11, 2026 11:10
- Widen getAuthorizationUrl() catch from HttpException|JsonException|CacheException to the documented base ItkOpenIdConnectException. The catch list was an incomplete enumeration of subtypes; widening to the public base is the contract the upstream library advertises.
- Document in the @throws block that other ItkOpenIdConnectException subtypes raised during provider init (BadUrlException etc.) are config-time errors and intentionally bubble as 500 rather than be coerced to 503.
- Move $this->fail() out of the try block in the two new test cases so a future refactor that drops the assertion line cannot silently weaken the tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@turegjorup
Copy link
Copy Markdown
Contributor Author

I think this has surfaced a need for refactoring the Exception design/structure, but out of scope for this PR.

@turegjorup turegjorup requested a review from jekuaitk May 11, 2026 10:09
@turegjorup turegjorup merged commit 53c62a5 into develop May 11, 2026
15 checks passed
@turegjorup turegjorup deleted the feature/login-controller-http-errors branch May 11, 2026 10:28
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.

3 participants