fix: #3630880 Delete tokens when their consumer is deleted
Closes https://www.drupal.org/project/simple_oauth/issues/3630880
What changed
Deleting a consumer now deletes its tokens. A token whose consumer is already gone gets a 401 with error="invalid_client" instead of a 500.
simple_oauth_consumer_delete()calls the newTokenExpiryTriggerHandlerInterface::handleConsumerDelete(), which deletes the consumer's tokens. It passes$include_refresh = TRUE. That finds no refresh tokens until #3630881 stores the client on them.TokenAuthUser::__construct()throwsOAuthServerException::invalidClient()when$token->get('client')->entitydoesn't load, instead of assigningNULLto the typedConsumerproperty.SimpleOauthAuthenticationProvider::authenticate()catchesOAuthServerExceptionfrom theTokenAuthUserconstructor and rethrows it asOAuthUnauthorizedHttpException, like the unpublished-consumer check added in #3436728.
Behavior change to review
The TokenAuthUser constructor already threw invalidClient() when a token had no user and its consumer had no default user. Nothing caught it, so that case returned a 500 as well. With the new catch, it returns a 401 like the deleted-consumer case.
API changes
New TokenExpiryTriggerHandlerInterface::handleConsumerDelete(). The interface allows new methods in minor releases.
Testing
TokenExpiryTriggerHandlerTest::testOnConsumerDelete(): deleting one consumer removes only its tokens.ClientCredentialsTest::testBearerTokenDeniedForDeletedConsumer(): re-creates an orphaned token after the delete and asserts a 401 witherror="invalid_client"from/oauth/debug?_format=json.
Without the fix, both tests fail. Without the TokenAuthUser change, the second test throws the TypeError from the issue.
AI-Generated: Yes. I wrote this fix and description with Claude Code and reviewed both.