0

Building Microservices With Django and pyJWT

Let me explain this in summarised manor, maybe someone can help me out been at this for too long

I have three microservices i.e.

  1. Authentication : Which creates the User and makes the token for a user using RS256 algorithm
  2. Student : which is basically a user type that needs to be verified using JWT
  3. Investor : which is also a user type that needs to be verified using JWT

[I have tried to make a generic create token function in authentication service something like]

data = {"id": user.uuid.hex, "type": user.user_type}
encoded = jwt.encode(data, private_key, algorithm="RS256")
return encoded

It is generating a correct token i have verified using JWT.io

In my student service i have created a middleware something like this

class JWTAuthenticationMiddleware(object):
    
    #Simple  JWT token based authentication.

    #Clients should authenticate by passing the token key in the "Authorization"
    #HTTP header, prepended with the string "Bearer ".  For example:

    #    Authorization: Bearer <UNIQUE_TOKEN>
   

    keyword = "Bearer"

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):

        auth = request.META.get("AUTHORIZATION", None)

        splitted = auth.split() if auth else []

        if len(splitted) == 2 and splitted[0] == self.keyword:
            if not splitted or splitted[0].lower() != self.keyword.lower().encode():
                return None
            if len(splitted) == 0:
                msg = _("Invalid token header. No credentials provided.")
                raise exceptions.AuthenticationFailed(msg)
            elif len(splitted) > 2:
                msg = _("Invalid token header. Token string should not contain spaces.")
                raise exceptions.AuthenticationFailed(msg)

            user = get_user(request)

            decoded = verify_token(auth)
            try:
                student = Student.objects.get(user_id=decoded.get("id"))
            except Student.DoesNotExist:
                student = Student.objects.update(user_id=decoded.get("id"))

        response = self.get_response(request)
        return response

My verify_token function looks like

def verify_token(token):
decoded = jwt.decode(token, JWT_AUTH["PUBLIC_KEY"], algorithms=["RS256"])
return decoded

I have also added my middleware in my settings just below authentication middleware

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "corsheaders.middleware.CorsMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.locale.LocaleMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "config.middleware.authentication.JWTAuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.common.BrokenLinkEmailsMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
]

I am just not able to decode my token and assign the payload to respective user type, Can someone help me out where i am going wrong? I have also tried using Authentication backend something like this, it doesn't works, have implemented simple_jwt_djangorestframework package but it doesn't decode my payload on student service and says invalid token so i don't want to add it for increasing unnecessary code too.

My viewset looks like this

class StudentViewset(viewsets.ViewSet):
    queryset = Student.objects.filter(is_active=True)
    serializer_class = StudentSerializer
    lookup_field = "uuid"
    permission_classes = [IsAuthenticated]

My error is always saying when i am using isAuthenticated as permission class

"message": "Authentication credentials were not provided.",
Chirag Bhatia
  • 11
  • 1
  • 2

2 Answers2

0

Maybe validating raw token should work :

decoded = verify_token(splitted[1])

Actually you don't have to implement it. There is simple jwt package for it. Install the package by its documentation and if it wouldn't work provide errors to help you.

Valery Ramusik
  • 1,473
  • 18
  • 19
  • Nope, it didn't work. It's still saying authentication credentials not provided, do i need to use rest framework's permission class or just need a way to implement in my middleware on;y? – Chirag Bhatia Mar 26 '21 at 03:45
0

To answer this question myself for future references

class JWTAuthenticationMiddleware(object):
    
    #Simple  JWT token based authentication.

    #Clients should authenticate by passing the token key in the "Authorization"
    #HTTP header, prepended with the string "Bearer ".  For example:

    #    Authorization: Bearer <UNIQUE_TOKEN>
   

    keyword = "Bearer"

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):

        auth = request.META.get("AUTHORIZATION", None)

        splitted = auth.split() if auth else []

        if len(splitted) == 2 and splitted[0] == self.keyword:
            if not splitted or splitted[0].lower() != self.keyword.lower().encode():
                return None
            if len(splitted) == 0:
                msg = _("Invalid token header. No credentials provided.")
                return JsonResponse(data=msg, status=403, safe=False)
            elif len(splitted) > 2:
                msg = _("Invalid token header. Token string should not contain spaces.")
                return JsonResponse(data=msg, status=403, safe=False)

            user = get_user(request)

            decoded = verify_token(auth)
            try:
                student = Student.objects.get(user_id=decoded.get("id"))
                return self.get_response(request)
            except Student.DoesNotExist:
                msg = _("Invalid User Not found")
                return JsonResponse(data=msg, status=403, safe=False)

couple of things that i was doing wrong was not passing a response when i found a student that's why middleware was not bypassed at that time, also exceptions cannot be used at middleware level middleware only returns HTTPResponses, thus i thought of using JsonResponse.

Chirag Bhatia
  • 11
  • 1
  • 2