Problem/Motivation
Deleting a consumer does not delete its tokens. The oauth2_token.client reference now points to a missing entity, and the next request that uses one of those access tokens fails with a 500:
TypeError: Cannot assign null to property Drupal\simple_oauth\Authentication\TokenAuthUser::$consumer of type Drupal\consumers\Entity\Consumer
TokenAuthUser::__construct() assigns $token->get('client')->entity to a typed Consumer property without checking for NULL. The token still passes JWT validation, because the signature and expiry are fine and the token row exists and isn't revoked.
Simple OAuth already deletes tokens when a consumer is updated (simple_oauth_consumer_update() → TokenExpiryTriggerHandler::handleConsumerUpdate()). Nothing handles delete.
Steps to reproduce
- Create a confidential consumer with the
client_credentialsgrant and a default user. - Request a token:
POST /oauth/tokenwithgrant_type=client_credentials. - Delete the consumer.
- Request
GET /oauth/debug?_format=jsonwithAuthorization: Bearer <token>.
Expected: 401. Actual: 500 with the TypeError above.
Proposed resolution
- Implement
hook_consumer_delete()and delete the consumer's tokens, mirroringhandleConsumerUpdate(). - In
TokenAuthUser::__construct(), throwOAuthServerException::invalidClient()when the client reference doesn't load. Sites with tokens already orphaned by past deletes then get a 401 instead of a 500.
Remaining tasks
- MR with a kernel test covering both changes.
AI disclosure
AI-Generated: Yes. I drafted this issue summary with Claude Code and reviewed it before filing.
Issue fork simple_oauth-3630880
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
mglamanComment #4
mglamanComment #5
attilatilman commentedComment #6
vidit.anjaria commentedComment #9
bojan_dev commentedMerged, thanks! Since #3630881 has been merged, refresh tokens now store their client, so I tightened
testOnConsumerDelete()to also check that refresh tokens are deleted.