feat(core): introduce interfaces for the main services - #709
Merged
Conversation
None of the main services of the library was final and none of them had an interface: they could neither be relied upon as closed, nor be decorated. They were left open only because the bundle extends them to dispatch events, which is also why the state of the JWS and JWE builders is protected instead of private. Every service now implements an interface - JWSBuilderInterface, JWSVerifierInterface, JWSLoaderInterface, JWEBuilderInterface, JWEDecrypterInterface, JWELoaderInterface, NestedTokenBuilderInterface, NestedTokenLoaderInterface, ClaimCheckerManagerInterface and HeaderCheckerManagerInterface - and the library type-hints those interfaces internally, so that a decorator can be injected anywhere a service is expected. The create() deprecated by #683 is left out of the two builder interfaces: the builders are immutable, there is no state to reset and the method is removed in 5.0.0. Extending the concrete classes is deprecated: they carry the @Final annotation and their constructor raises a deprecation notice. The bundle gains a decorator for every event dispatching service and deprecates the inheritance based ones, which keep their class names, their service ids and their behaviour. Each service is now also aliased with its interface, so that "MyInterface $fooJwsBuilder" can be autowired the same way the concrete class already was. The event dispatching verifier and decrypter of the bundle used to drop the callable the loaders pass as a sixth argument to observe the discarded keys, so the reason of a failure was lost as soon as the bundle services were used. They forward it now, as the new decorators do.
Spomky
force-pushed
the
feature/service-interfaces
branch
from
August 29, 2026 16:21
3130452 to
2b48f1f
Compare
This was referenced Aug 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #684.
What
Every main service of the library now implements an interface, the library type-hints those interfaces internally, and the bundle ships a decorator for each of its event dispatching services. Nothing changes for existing code: no signature is narrowed, no service id moves, no runtime type changes.
Library
New interfaces, implemented by the existing classes:
Jose\Component\Signature\JWSBuilderInterfaceJWSBuilderJose\Component\Signature\JWSVerifierInterfaceJWSVerifierJose\Component\Signature\JWSLoaderInterfaceJWSLoaderJose\Component\Encryption\JWEBuilderInterfaceJWEBuilderJose\Component\Encryption\JWEDecrypterInterfaceJWEDecrypterJose\Component\Encryption\JWELoaderInterfaceJWELoaderJose\Component\NestedToken\NestedTokenBuilderInterfaceNestedTokenBuilderJose\Component\NestedToken\NestedTokenLoaderInterfaceNestedTokenLoaderJose\Component\Checker\ClaimCheckerManagerInterfaceClaimCheckerManagerJose\Component\Checker\HeaderCheckerManagerInterfaceHeaderCheckerManagerJWSLoader,JWELoader,NestedTokenBuilderandNestedTokenLoaderaccept and return the interfaces instead of the concrete classes, so a decorator can be injected into any of them.Extending the concrete classes is deprecated: they carry a
@finalannotation and their constructor raises a deprecation notice throughInheritanceChecker. The event dispatching services of the bundle are excluded from that notice - they are deprecated themselves and cannot be avoided in 4.3 - so the notice only ever points at code the user owns.Bundle
EventDispatchingJWSBuilder,EventDispatchingJWSVerifier,EventDispatchingJWSLoader,EventDispatchingJWEBuilder,EventDispatchingJWEDecrypter,EventDispatchingJWELoader,EventDispatchingNestedTokenBuilder,EventDispatchingNestedTokenLoader,EventDispatchingClaimCheckerManagerandEventDispatchingHeaderCheckerManager. They dispatch the same events without inheriting anything.Services\*classes are annotated@deprecatedand keep doing the work in 4.3: swapping them for the decorators changes the runtime type ofjose.jws_builder.*and friends, which would break everyJWSBuilder $buildertype hint. That swap belongs to 5.0.0.JWSBuilderInterface $builder1JwsBuilderautowires exactly likeJWSBuilder $builder1JwsBuilderdoes.One bug fixed along the way
Services\JWSVerifier::verifyWithKeySet()andServices\JWEDecrypter::decryptUsingKeySet()declared five parameters and forwarded only those five to the parent, dropping the callable the loaders pass as a sixth argument to observe the discarded keys. The exception chaining added in #699 was therefore lost as soon as the bundle services were in use. Both now read and forward it withfunc_num_args()/func_get_arg(5), as the new decorators do.Deliberate limitations
create()is deliberately absent from the two builder interfaces. Make the JWS/JWE builders truly immutable and deprecate create() #683 made the builders immutable and deprecated it, so there is no state to reset and the method disappears in 5.0.0. The concrete classes still carry it, so nothing existing breaks.signature_algorithm,key_encryption_algorithm) that a decorator cannot read. The decorators report the key and the headers they were given instead; the class docblocks say so. Exposing that data through the events themselves is part of the 5.0.0 plan.Component\NestedToken\NestedTokenLoaderFactory::create()and its bundle counterpart, which is a change of its own.Backward compatibility
Constructor parameters were widened from classes to interfaces (contravariant, safe for callers).
JWSLoader::getJwsVerifier(),JWSLoader::getHeaderCheckerManager(),JWELoader::getJweDecrypter()andJWELoader::getHeaderCheckerManager()now return the interface; the interfaces expose the full public API of the classes they replace, so no call site can break. Everything else is additive.Checks
Rebased on top of #706.
phpunit(949 tests),ecs,phpstan,deptracandrector --dry-runare green. The PHPStan baseline was regenerated: it gained the entries for the bundle's own use of its now deprecated services and lost fourmissingType.iterableValueentries that the new interface docblocks fix.