JWT Token Invalid Signature / Not verifyable

Created on 13 December 2017, over 7 years ago
Updated 23 January 2024, about 1 year ago

I've tried to test the module for d8 (after applied πŸ› Token endpoint gives error when using cryptotokens (D8) Needs work ) and d7 using https://openidconnect.net and & https://developers.google.com/oauthplayground/ .

I see a problem with the token after I get it.... The signature returned is invalid/not verified (tested in https://jwt.io )

Any help?

πŸ› Bug report
Status

Active

Version

1.0

Component

Code

Created by

πŸ‡¨πŸ‡­Switzerland Zekvyrin Switzerland / Greece

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • πŸ‡ΊπŸ‡ΈUnited States torgosPizza Portland, OR

    We are currently experiencing this on our live production site (Drupal 7) and based on what I see in the D8 code, the latest version of the module may suffer from a similar problem.

    Right now, applying patches adding classes such as JwtAccessTokenStorage are helpful, but the issue lies in the fact that the private and public keys are both "global". Most of the time this works especially if users are not hitting these frequently.

    But, we have seen one particular scenario play out quite frequently (using JWTs, access token expiry = 3600, refresh token = 90 days):

    1. A user generates a JWT right before new server keys are needed. (Example: if server keys get generated every day at 23:59:59, our test user should generate their token at 22:59:59.)
    2. Server cron runs and new keys are generated.
    3. The user continues to make requests to endpoints with the JWT from Step 1 because it is valid for 2 more hours.

    Expected result: the access token (which is not yet expired) is accepted as valid.

    Actual result: "invalid_token" error because the global keys no longer decrypt the token.

    In the D7 module this is due to 1) the keys being global and 2) not being stored with the token. Even when we have configured a Public Key in the settings area, this key is ignored in the encode/decode process. It does appear the latest code follows a similar pattern:

      public function getPublicKey($client_id = NULL) {
        // The library allows for per-client keys. The module uses global keys that
        // are regenerated every day, following Google's example.
        $keys = Utility::getKeys();
        return $keys['public_key'];
      }
    

    I'm not sure how to properly address this, but part of the issue IMO seems to be to ensure that the public key used to encode the JWT is stored in the token itself on the server. If that is not possible, it should be changed so that the public key is NOT regenerated so frequently; while the code block's comments above indicate we are "following Google's example," what the Drupal module neglected to copy was low frequency of public key rotation:

    Since Google changes its public keys only infrequently, you can cache them using the cache directives of the HTTP response ...

    In the Drupal side of things, private and public keys are rotated every day during oauth2_server_cron(), resulting in frequent access tokens being erroneously seen as "invalid". One other solution might be to make the access tokens only expire after 30 minutes, but we sell video content that is sometimes 2 hours in length, and it's possible that this could cause errors while the user is viewing their purchased content. In my opinion the keys system should be made more flexible to account for this behavior.

  • πŸ‡ΊπŸ‡ΈUnited States torgosPizza Portland, OR

    This seems related and relevant: πŸ› The JWT must contain the kid Active

Production build 0.71.5 2024