Skip to content

Invalid JWT signature because of hashed client secret #1239

Closed
@dnsv

Description

@dnsv

Describe the bug

I'm using next-auth on the frontend and the latest django-oauth-toolkit with OIDC enabled and HS256 as the algorithm on the backend. After authorizing my oauth application I get the error "failed to validate JWT signature" in next-auth.

The JWT token provided by django-oauth-toolkit seems to be incorrect. It's prepared in oauth2_provider.oauth2_validators.finalize_id_token. The culprit is the jwk_key that's used for signing the token. It's generated with the client secret, which is being hashed since v2.0.0.

jwt_token.make_signed_token(request.client.jwk_key)

I'm assuming that hashing was added under the assumption that the raw secret isn't needed anymore after it's created, but that doesn't seem to be the case (see line 224).

@property
def jwk_key(self):
if self.algorithm == AbstractApplication.RS256_ALGORITHM:
if not oauth2_settings.OIDC_RSA_PRIVATE_KEY:
raise ImproperlyConfigured("You must set OIDC_RSA_PRIVATE_KEY to use RSA algorithm")
return jwk.JWK.from_pem(oauth2_settings.OIDC_RSA_PRIVATE_KEY.encode("utf8"))
elif self.algorithm == AbstractApplication.HS256_ALGORITHM:
return jwk.JWK(kty="oct", k=base64url_encode(self.client_secret))
raise ImproperlyConfigured("This application does not support signed tokens")

To Reproduce

I've created a test repo: https://github.com/dnsv/auth-test

  1. Setup Django (I'm using Python 3.11):

    1. poetry install
    2. poetry run python manage.py runserver
    3. poetry run python manage.py migrate
    4. poetry run python manage.py createsuperuser.
  2. Login into admin.

  3. Create a new Oauth application:

  4. Create the file frontend/.env:

    OAUTH_CLIENT_ID=...
    OAUTH_CLIENT_SECRET=...
    
  5. Setup Next.js (I'm using node v18.12.1, but i probably works the same with lower versions).

    1. cd frontend
    2. yarn install
    3. yarn dev
  6. Go to http://localhost:3000/ and try to sign it. You'll get the error shown in the console after the authorization step.

Highlights from the backend setup:

# backend/base/settings.py

OAUTH2_PROVIDER = {
    "OIDC_ENABLED": True,
    "OAUTH2_VALIDATOR_CLASS": "backend.oauth2.utils.CustomOAuth2Validator",
    "SCOPES": {
        "openid": "OpenID Connect scope",
    },
}

# backend/oauth2/utils.py

from oauth2_provider.oauth2_validators import OAuth2Validator

class CustomOAuth2Validator(OAuth2Validator):
    oidc_claim_scope = None

    def get_additional_claims(self, request):
        return {
            "id": request.user.id,
            "given_name": request.user.first_name,
            "family_name": request.user.last_name,
            "name": f"{request.user.first_name} {request.user.last_name}",
            "email": request.user.email,
        }

Expected behavior

Being able to login :)

Version

  • I have tested with the latest published release and it's still a problem.
  • I have tested with the master branch and it's still a problem.

Additional context

N/A

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions