We're using the 'Simple OAuth' and 'jsonapi' modules for the front end authentication in Angular of our decoupled Drupal project.

We've noticed that when the user credentials are correct but the token is expired the header response is still 200 'ok' with a message that indicates that the Token no longer valid.

But we need a 400/401 or 403, like it is described in the oath documentations.

Is there a reason why this is implemented like this? Or is there a way to alter the response?

  • I don't see message Token no longer valid coming from either one of two modules you've mentioned. Not even from underlaying composer dependencies. Can you verify that there is no custom code that subscribes to the kernel request and returns 200 with Token no longer valid message?
    – zaporylie
    Commented Jun 18, 2018 at 12:04
  • @zaporylie, Hi, thanks for your response. What I meant was that it gives a message that indicates that the token has expired, not that explicit message. Sorry, I see that I didn't explain that very clearly. But the main problem is that it gives status 200 ok, and it's only visible in the meta data that there is a problem.
    – M M
    Commented Jun 18, 2018 at 13:46
  • Do you mean that when you use an expired token on one of the jsonapi collections (e.g. /jsonapi/user/user) you get empty data array and meta full of errors? And if it's not a collection which gives you the unexpected outcome, can you specify which resource provides invalid status code?
    – zaporylie
    Commented Jun 18, 2018 at 20:46
  • Indeed when I use an expired token on /jsonapi/user/user (for example) I receive an empty data and meta full of errors while the status is 200 ok. I've tested this with postman and our front-end colleagues had the same while testing in their application.
    – M M
    Commented Jun 19, 2018 at 7:39
  • @M M, does my answer make any sense to you?
    – zaporylie
    Commented Jun 20, 2018 at 9:10

3 Answers 3


Is there a reason why this is implemented like this?

200 ok is expected status code for collection resources, even if one, many, or all entities were excluded from the collection resource for access reasons.

From https://www.drupal.org/project/jsonapi/issues/2853066:

The status code for a "collection resource" should be entirely distinct from any or all of the entities represented at that resource.

Unless there is an access control mechanism that is explicitly a prerequisite for accessing any list of entities of a given type that we can leverage, then it must be assumed that any consumer must have access to any collection resource.

It is completely consistent with REST to return a 200 response to an empty collection, even when all those entities have been elided for access reasons.

Or is there a way to alter the response?

Of course, you can. Check the documentation about altering routes and providing custom access tagged service:

Finally, the link you provided in the question is to oauth specs, and is irrelevant to jsonapi. Oauth resource in Drupal (/oauth/token) will correctly give you 4xx in case of any errors when obtaining a new token.

  • If a 200 response is correct, how is one supposed to determine if a token has expired? Commented Mar 1, 2020 at 10:35


I found a method that works for me.


namespace Drupal\modulename\Routing;

use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;

 * Listens to the dynamic route events.
 * https://www.drupal.org/docs/8/api/routing-system/altering-existing-routes-and-adding-new-routes-based-on-dynamic-ones
class ModuleNameRouteSubscriber extends RouteSubscriberBase {

   * {@inheritdoc}
  protected function alterRoutes(RouteCollection $collection) {
    //issue is this only works for JUST /rahapi and not anything else
    //if ( $route = $collection->get('jsonapi.resource_list') ) {
    //  $route->setRequirement('_user_is_logged_in', 'TRUE');

    foreach ($collection->all() as $route) {
      if (strpos($route->getPath(), '/jsonapi') === 0 ) {
        $route->setRequirement('_user_is_logged_in', 'TRUE');

That goes in modulename/src/Routing/ModuleNameRouteSubscriber.php

Then this goes in modulename/modulename.services.yml

    class: Drupal\modulename\Routing\ModuleNameRouteSubscriber
    arguments: []
      - { name: event_subscriber }

So I found it by going here: https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Routing%21RouteSubscriberBase.php/class/RouteSubscriberBase/8.2.x

So I'm extending that... and I see there are many other things that extend it. Like this one for /admin. So I did monkey-see-monkey-do and generated the code above. I hope my sample code works for you.


Thank you zaporylie for pointing me in the initial direction.


Before this implimentation you can call one more api which debugs the token. Just provide token in header and in the results we will get token expiration details.

api :- http://your_url/oauth/debug?_format=json

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.