When working with Django OAuth Toolkit, using OIDC if you supply openid
as the scope
in request you get a id_token
with access token.
This ID Token can initially be used to identify the user you have got access token for and also create a session.
{
"aud": "audience",
"iat": 1681801110,
"at_hash": "hash of included access token",
"sub": "1",
"given_name": "Dushyant",
"preferred_username": "dsh",
"iss": "authEndpointurl",
"exp": 1681837110,
"auth_time": 1681567804,
"jti": "tokenid"
}
But I wish to modify the claims in this JWT ID Token, it reveals the primary key of the database of Authorization Server as the unique id
of the user which i don't want in the claim called sub
.
I want to use another unique key as the value of sub
claim.
I tried overriding the response a Custom Backend:
class CustomOAuthBackend(OAuthLibCore):
def __init__(self, server):
super().__init__(server)
def create_token_response(self, request):
response_data = super().create_token_response(request)
#Modify the response here
return response_data
And added this as the Custom Backend in the settings.
"OAUTH2_BACKEND_CLASS":"pathto.CustomOAuthBackend",
I haven't written any modification code for the response here since the token here is already created When I am calling the original create_token_response.
I want to override it in a way that I can modify the claims dict, I am not sure where it is getting created. We get the id_token all prepared. I want to override the process of creating id_token and change sub
claim value.
Let me know if any more information is required.
Update 1:
While looking for a possible solution, found oauth2_provider.oauth2_validators have methods get_oidc_claims()
and get_id_token_dictionary()
which looks like could lead to a possible solution. Figuring out how to use it.
There is a write up in the code
This method is OPTIONAL and is NOT RECOMMENDED.
finalize_id_token
SHOULD be implemented instead. However, if you want a full control over the minting of theid_token
, you MAY want to overrideget_id_token
instead of usingfinalize_id_token
.
This write up talks about get_id_token()
method. Going through the code I see that finalize_id_token()
is the method where JWT is created from claims.
This method calls get_id_token_dictionary
then this internally calls get_oidc_claims()
then this calls get_claim_dict(request)
. get_claim_dict(request) only takes a request while others take token etc also. This method looks correct to override as this actually adds that sub
claim to claims.
def get_claim_dict(self, request):
if self._get_additional_claims_is_request_agnostic():
claims = {"sub": lambda r: str(r.user.id)}
else:
claims = {"sub": str(request.user.id)}
# https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
if self._get_additional_claims_is_request_agnostic():
add = self.get_additional_claims()
else:
add = self.get_additional_claims(request)
claims.update(add)
return claims
I can get claims from this modify it and return the new updated claims.
I was able to do it by the same process I mentioned in the question.
At the end I override get_claim_dict(self, request)
method.
class CustomOAuth2Validator(OAuth2Validator):
def get_claim_dict(self, request):
claims = super().get_claim_dict(request)
claims["sub"] = lambda request: get_user_guid(request=request)
return claims
I override the get_claim_dict in OAuth2Validator.
Add this validator as custom validator in django settings "OAUTH2_VALIDATOR_CLASS": "pathTo.CustomOAuth2Validator",
On decoding the JWT ID Token you will get the new value.