So I've been trying to build a Django project that handles authentication centrally on a standalone basis using django-rest-framework-simplejwt. And other Django Rest Framework projects that use this for authentication. All projects will have their own databases.
I am not quite sure what goes into the database section in settings.py of both the auth project and other projects. The documentation mentions something about JWTTokenUserAuthentication backend as an experimental feature and is quite inadequate.
I have done some research and found I may have to use a remote user login or set up a proxy server. Can someone point me in the right direction?
I'm not sure what you're asking, but I can clarify that
JWTTokenUserAuthentication is basically authenticating solely on the
validity of the token. The default authentication mechanism introduced in
the docs validates the token then checks that the user ID is in the
database using the authenticate method.
On Fri, Sep 25, 2020 at 12:55 AM Abishek D notifications@github.com wrote:
So I've been trying to build a Django project that handles authentication
centrally on a standalone basis using django-rest-framework-simplejwt.
And other Django Rest Framework projects that use this for authentication.
All projects will have their own databases.I am not quite sure what goes into the database section in settings.py of
both the auth project and other projects. The documentation mentions
something about JWTTokenUserAuthentication backend as an experimental
feature and is quite inadequate.I have done some research and found I may have to use a remote user login
or set up a proxy server. Can someone point me in the right direction?—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/SimpleJWT/django-rest-framework-simplejwt/issues/307,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AOLG4VU54JE4YO6SYYZTMQDSHQPCLANCNFSM4RZC3RYQ
.
@Andrew-Chen-Wang Thanks for your response.
In a microservices environment, multiple Django projects will be hosted separately with their own separate database and will not contain the user table to check the user ID.
Only one Django project(central authentication) will contain the user table along with the user ID, in this scenario, I suppose django-rest-framework-simplejwt's JWTTokenUserAuthentication can be used for SSO(Single Sign-On) according to the documentation provided here.
So, I am wondering what other settings I must do in order for this to lookup user ID from this separately hosted Django project(meant only for authentication) apart from
REST_FRAMEWORK = {
...
'DEFAULT_AUTHENTICATION_CLASSES': (
...
'rest_framework_simplejwt.authentication.JWTTokenUserAuthentication',
)
...
}
included in the documentation.
Uh Django is more typically known for being a monolith type web framework. If I'm understanding this correctly, you only have one server with the user table; the rest of your servers have a different database without the user table right?
In that case, if you use JWTTokenUserAuthentication, what you have now is perfectly fine. That means SimpleJWT only uses PyJWT to make sure that the token is valid. Just make sure you set the SIGNING_KEY to be the same across all you servers (assuming you have a different SECRET_KEY for each Django, which SimpleJWT defaults to if you don't set a signing key).
There's an upcoming PR regarding setting audiences, but I wouldn't count on that just yet since, although it's in production, it's not been tested by me. Hope that helps!
@Andrew-Chen-Wang Yes, you got it correct. There is one server with a user table and the rest of the servers hosts its own application-related services without the user table similar to Google, how one account is used for multiple products like Gmail, Drive, etc.
So if I understand you correctly, all I need to do is make sure SECRET_KEY (SIGNING_KEY) needs to be set the same across all the project's settings.py file along with 'rest_framework_simplejwt.authentication.JWTTokenUserAuthentication'.
And when you say it's not tested enough and wouldn't count on it, do you mean there is a security risk with this kind of architecture(JWTTokenUserAuthentication). I am assuming that is if the SECRET_KEY is compromised or any other thing?
So if I understand you correctly, all I need to do is make sure SECRET_KEY (SIGNING_KEY) needs to be set the same across all the project's settings.py file along with 'rest_framework_simplejwt.authentication.JWTTokenUserAuthentication'
Yes, however I encourage you to generate your own SIGNING_KEY rather than using the SECRET_KEY since you want to rotate each of these keys. You can generate a new secret key by just generating another Django project or looking for their util function that generates the secret key. I say this since you need to look at the requirements for your encryption standard to make sure your key is long enough (e.g. HS256 and HS512 require different length keys).
similar to Google, how one account is used for multiple products like Gmail, Drive, etc.
At Google, we only give a user one account that's used across all subdomains. Even when you take into account YouTube.com, the table is the same, but the architecture is a little different than when we think typical relational database ;)
And when you say it's not tested enough and wouldn't count on it, do you mean there is a security risk
Sorry, I was referring to the new PR, not this feature. This feature has been tested enough to be OK.
@Andrew-Chen-Wang Noted! Thanks for the info and for pointing me in the right direction.
@Andrew-Chen-Wang Is there a way to use the token user received from the JWT token in models.py of microservices Django project so as to establish a relationship with the fake User model?
I'm looking to do something like this:-
models.py
from django.db import models
"""Don't want to use this User instance"""
# from django.contrib.auth.models import User
class Book(models.Model):
user = models.ForeignKey(User, default=1, on_delete=models.CASCADE)
name = models.CharField(max_length=120)
price = models.FloatField()
The TokenUser model that you get from using JWTTokenUserAuthentication backend comes from here: https://github.com/SimpleJWT/django-rest-framework-simplejwt/blob/969118276fcbd49f4f5d88756dd36f2427e25dbd/rest_framework_simplejwt/models.py#L9-L17
It's similar to how if an anonymous user pings a view, then you'll get django.contrib.auth.models.AnonymousUser. What you should do is that you need to grab the ID by doing:
tokenuser.id
And then using your own model, do User.objects.get(id=tokenuser.id)
@Andrew-Chen-Wang I am able to fetch the user.id from token as you suggested but the model tries to lookup the user table in its own database and throws an error django.db.utils.IntegrityError: insert or update on table "core_book" violates foreign key constraint "core_book_user_id_55b2f8ca_fk_auth_user_id"
DETAIL: Key (user_id)=(1) is not present in table "auth_user"
Here's how my code looks:-
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Book(models.Model):
user = models.ForeignKey(User, default=1, on_delete=models.CASCADE)
name = models.CharField(max_length=120)
price = models.FloatField()
views.py
from django.shortcuts import render
from rest_framework import viewsets, permissions
from .models import Book
from .serializers import BookSerializer
from django.contrib.auth.models import User
from rest_framework.response import Response
from rest_framework.status import HTTP_200_OK, HTTP_400_BAD_REQUEST
# Create your views here.
class BookViewset(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
permission_classes = [permissions.IsAuthenticated]
# def get(self, request):
# print("hello")
# print(self.request.user)
# return self.request.user
def post(self, request, *args, **kwargs):
user = User.objects.get(id=tokenuser.id)
print("user")
print(user)
return Response({"message": ""}, status=HTTP_200_OK)
That's because you should be doing request.user.id in this case. tokenuser was just an example variable; otherwise, you've got a variable that was never even declared.
You should also not have default=1 in your FK attribute. That's just dangerous...
Most helpful comment
That's because you should be doing request.user.id in this case.
tokenuserwas just an example variable; otherwise, you've got a variable that was never even declared.You should also not have default=1 in your FK attribute. That's just dangerous...