Document AuthenticatorInterface DI binding requirement for autowired Authentication middleware - #127
Conversation
Authentication's constructor requires AuthenticatorInterface, with no
default implementation for a container to autowire it to. When a
framework builds the middleware via autowiring rather than manual
construction (e.g. applying it to a route by class name, as
yiisoft/router groups commonly do), an unbound AuthenticatorInterface
fails with a message that never names the actual gap:
No definition or class found for "Yiisoft\Auth\Middleware\Authentication" ID.
No definition or class found or resolvable for "Yiisoft\Auth\AuthenticatorInterface"
while building "Yiisoft\Auth\Middleware\Authentication" -> "Yiisoft\Auth\AuthenticatorInterface".
Hit for real in a production Yii3 app after adopting 3.3.0's
AuthenticatorInterface split: the middleware had been referenced via
autowiring across most of the app's routes with no binding ever
configured, working only because it had never actually been
constructed until a compiled DI container cache was invalidated by an
unrelated composer update.
New "Using with a DI container" README section documents the binding
requirement with an example, and calls out the equally valid
alternative when a route doesn't need HTTP-challenge-style
authentication at all: don't apply this middleware there, rather than
binding an authenticator you don't otherwise use just to satisfy the
container.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
For anyone curious what applying this pattern actually looks like end-to-end in the same app that hit |
There was a problem hiding this comment.
Pull request overview
This PR updates the documentation to clarify that when Yiisoft\Auth\Middleware\Authentication is constructed via DI/autowiring, the DI container must be configured with a binding for Yiisoft\Auth\AuthenticatorInterface, otherwise middleware resolution fails.
Changes:
- Add a “Using with a DI container” section to the README.
- Provide an example DI definition intended to bind
AuthenticatorInterfaceto a concrete authenticator implementation.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| e.g. recurring invoice monthly cron | ||
|
|
||
| ```php | ||
| use App\Invoice\InvRecurring\CronTokenRepository; | ||
| use Yiisoft\Auth\AuthenticatorInterface; | ||
| use Yiisoft\Auth\Method\HttpBearer; | ||
|
|
||
| return [ | ||
| AuthenticatorInterface::class => static fn (CronTokenRepository $cronTokenRepository): HttpBearer => | ||
| new HttpBearer($cronTokenRepository), | ||
| ]; | ||
|
|
||
| ``` |
Summary
Authentication's constructor requiresAuthenticatorInterface, and the package ships no defaultimplementation for a container to autowire it to. That's fine when it's constructed manually (as the
existing "General usage" example shows), but when a framework builds the middleware via autowiring instead —
applying it to a route by class name, as
yiisoft/routergroups commonly do(
->middleware(Authentication::class)) — an unboundAuthenticatorInterfacefails with a message that nevernames the actual gap:
We hit this for real in a production Yii3 app after adopting 3.3.0's
AuthenticatorInterfacesplit(#113/#115): the middleware had been referenced via autowiring across most of the app's routes with no
binding ever configured — it had simply never actually been constructed until a compiled DI container cache
was invalidated by an unrelated
composer update, at which point every one of those routes started 500ing.This PR adds a short "Using with a DI container" section to the README documenting the binding requirement,
with an example, and explicitly naming the equally valid alternative when a route doesn't need
HTTP-challenge-style authentication at all: don't apply this middleware there, rather than binding an
authenticator you don't otherwise use just to satisfy the container.
Related write-up
For anyone wanting the fuller story (including the exact production exception, the fix, and a plain-English
explainer on when an app would actually need
WWW-Authenticate-style auth vs. session-based login):https://github.com/rossaddison/invoice/blob/main/docs/AUTHENTICATION_DI_CRASH_FIX_AUGUST_2026.md and
https://github.com/rossaddison/invoice/blob/main/docs/WWW_AUTHENTICATE_VS_SESSION_AUTH_AUGUST_2026.md
(the latter also has Persian/Portuguese translations, if useful to anyone on the team or in the wider
community).
Happy to adjust wording/placement if you'd rather this live in
docs/internals.mdinstead, or if you'dprefer the constructor itself to throw a more specific exception rather than (or in addition to) documenting
it — from what I can tell the current message actually originates in
yiisoft/di's generic resolutionfailure, not in this package, so a code-level fix may not be in scope here at all.