A silenced error for JWT Stateless Authentication during token validation #832
Description
Context
I'm using Keycloak to implement SSO with Django, and I found this library. I used JWTStatelessUserAuthentication
for my default authentication class as stated in the docs. However, i was having trouble with the validation process when the frontend passed in the JWT token to django on a protected endpoint. It keeps giving me 401 Unauthorized with the message "Token is invalid or expired". The message was quite vague as i couldn't debug the code as there is no logging output other than the Unauthorized response.
Issue
With Keycloak, you would get the JWK via https://xxx/realms/xxx/protocol/openid-connect/certs
endpoint. What I found was that it was raising a Forbidden error from PyJWKClient
when it does PyJWKClient.fetch_data()
, I couldn't see this error due to the generic error raised by this try-except.
For more detail, Keycloak rejects (gives Forbidden) on GET requests that does not have a user-agent header, which PyJWKClient
does not by default.
Current solution
To solve my issue i had to override Token and patch the token_backend
Code
from rest_framework_simplejwt.tokens import AccessToken
class KeycloakAccessToken(AccessToken):
token_type = "Bearer" # token_type is not stated within payload, but `typ` exist
def get_token_backend(self) -> "TokenBackend":
backend = super().get_token_backend()
backend.jwks_client.headers = {"User-Agent": "Keycloak-python-urllib"}
return backend
settings.py
SIMPLE_JWT = {
"ALGORITHM": "RS256",
"ISSUER": KEYCLOAK_ISSUER,
"JWK_URL": JWKS_URL,
"SIGNING_KEY": None,
"VERIFYING_KEY": None,
"USER_ID_CLAIM": "sub",
"TOKEN_TYPE_CLAIM": "typ",
"LEEWAY": 5,
"AUTH_HEADER_TYPES": ("Bearer",),
"AUTH_TOKEN_CLASSES": ("search.token.KeycloakAccessToken",),
}
Discussion
It would be helpful if there is a way to debug these, have verbose output with logging DEBUG level. It would also be good to be able to override PyJWKClient
args for TokenBackend
init.