djangorestframework-simplejwt icon indicating copy to clipboard operation
djangorestframework-simplejwt copied to clipboard

Allow User creation after token validation.

Open cristobalmackenzie opened this issue 3 years ago • 5 comments

Hi ! I've successfully set up a Django project that validates JWTs from AWS Cognito using the JWK_URL setting.

I ran into a problem though, which is the fact that users making requests to my API don't necessarily have a corresponding record in the local User table, so JWTAuthentication.get_user runs into problems. I would like to have the chance to create these users.

I ended up subclassing JWTAuthentication and made it work by overriding the get_user method.

I think this could be a good improvement to the library, and is probably a common requirement from users in positions like mine (using external auth).

With a bit of guidance as to how exactly this could/should be implemented, I'd be glad to work on a small PR.

cristobalmackenzie avatar Feb 22 '22 18:02 cristobalmackenzie

Hi @cristobalmackenzie Good to hear! What you can do is create an import string that allows users to specify how to get the user. An example is the authentication rule callable. Then, in get_user itself, you can check the api settings to see if a callable was set. If it was, pass the data (from the validation) to the callable and return the result. If a callable was not set, you can run the code that is currently there. If that's confusing, create a PR of what you think we should we and we can discuss further :)

Andrew-Chen-Wang avatar Feb 22 '22 19:02 Andrew-Chen-Wang

Hi @Andrew-Chen-Wang , this is clear and sounds like a good solution to me. I'll work on it and check-in with any updates.

cristobalmackenzie avatar Feb 22 '22 19:02 cristobalmackenzie

Hi @cristobalmackenzie I'm running into this as I want to use auth0, and was curious how you went about solving this in the end.

Cheers.

rj76 avatar Apr 08 '22 17:04 rj76

I solved this by overriding get_user in a subclass of django_rest_framework_simplejwt.authentication.JWTAuthentication. My get_user validates application-specific claims, resolves any conflict with existing users on user identifiers, and creates users if necessary. Our custom user model captures the iss and sub claims as a unique identifier tuple for the user.

Some gotchas you might encounter:

  • email claim: Django normalizes email addresses via get_user_model().objects.normalize_email(). Domains are case insensitive and local portion is case sensitive (shouldn't matter but in some situations it might).
  • iss and sub are case sensitive claims. If you are saving these fields in your database to query against later, make sure those fields are using a case-sensitive collation.

dcopso avatar Dec 03 '22 22:12 dcopso

@cristobalmackenzie, @dcopso . I've been trying setup AWS Cognito using JWK_URL, but not working, can you give me a example, please, how you did this setup.

My settings.py

SIMPLE_JWT = {
    "JWK_URL": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXXXX/.well-known/jwks.json",
    "ALGORITHM": "RS256",
    "AUDIENCE": "<my cognito app client>",
    "ISSUER": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXXXX",
}

myview.py

from rest_framework_simplejwt.authentication import JWTAuthentication

class TesteViewSet(
    mixins.ListModelMixin,
    viewsets.GenericViewSet,
):
    queryset = MyModel.objects.all()
    serializer_class = TesteSerializer
    authentication_classes = [JWTAuthentication]

What more I need to do?

Tks in advance, :)

mateuspadua avatar Mar 18 '24 11:03 mateuspadua