GithubHelp home page GithubHelp logo

jazzband / djangorestframework-simplejwt Goto Github PK

View Code? Open in Web Editor NEW
3.9K 57.0 653.0 837 KB

A JSON Web Token authentication plugin for the Django REST Framework.

Home Page: https://django-rest-framework-simplejwt.readthedocs.io/

License: MIT License

Python 98.72% Makefile 0.69% JavaScript 0.60%

djangorestframework-simplejwt's Introduction

djangorestframework-simplejwt's People

Contributors

2ykwang avatar abczzz13 avatar adrianodidio avatar ajhodges avatar andrew-chen-wang avatar aqeelat avatar bandeveloper avatar davesque avatar dgmouris avatar domdinicola avatar dresdn avatar egor-oop avatar felixxm avatar fergyfresh avatar hramezani avatar inti7ary avatar jezdez avatar johnthagen avatar jpadilla avatar kiraware avatar m2mbr avatar mahdirahimi1999 avatar mateusz-slisz avatar pre-commit-ci[bot] avatar t-io avatar thomasrockhu-codecov avatar vainu-arto avatar waketzheng avatar xrmx avatar yaser-amiri avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

djangorestframework-simplejwt's Issues

Token verification is passing after token rotation

After token refreshing (with refresh token rotation enabled) old refresh token is still passing validation.

Blacklist app is in INSTALLED APPS

Settings:
SIMPLE_JWT = { 'ROTATE_REFRESH_TOKENS': True, 'BLACKLIST_AFTER_ROTATION': True, }

Usage of authenticate function in TokenObtainSerializer

class TokenObtainSerializer(serializers.Serializer):
    username_field = User.USERNAME_FIELD

    def __init__(self, *args, **kwargs):
        super(TokenObtainSerializer, self).__init__(*args, **kwargs)

        self.fields[self.username_field] = serializers.CharField()
        self.fields['password'] = PasswordField()

    def validate(self, attrs):
        self.user = authenticate(**{
            self.username_field: attrs[self.username_field],
            'password': attrs['password'],
        })
        if self.user is None or not self.user.is_active:
            raise serializers.ValidationError(
                _('No active account found with the given credentials'),
            )

        return {}

TokenObtainSerializer is using authenticate function which makes it impossible use something else than User.USERNAME_FIELD for authentication.

Let's say I set username_field to something else than User.USERNAME_FIELD, for example email (and assume User.USERNAME_FIELD equals to username). Is this going to work? authenticate function is going to use User.USERNAME_FIELD = username but serializer has received email field.

Naming issue

To what extent TokenObtainSerializer has anything to do with tokens? It can be misleading that serializer that has at least token is it's name is always returning empty dictionary.

What do you think about naming that more in terms of authentication? AuthenticationSerializer or something like that?

Implementation of validate method

Let's look at:

class TokenObtainPairSerializer(TokenObtainSerializer):
    @classmethod
    def get_token(cls, user):
        return RefreshToken.for_user(user)

    def validate(self, attrs):
        data = super(TokenObtainPairSerializer, self).validate(attrs)

        refresh = self.get_token(self.user)

        data['refresh'] = text_type(refresh)
        data['access'] = text_type(refresh.access_token)

        return data

Why refresh and access fields are added in validate method? This method is supposed to validate data returned by to_internal_value, why not add those to keys in to_internal_value?

In my case, I had to override TokenObtainPairSerializer in the following way:

class CustomTokenObtainPairSerializer(CustomTokenObtainSerializer, TokenObtainPairSerializer):
    access = serializers.CharField(read_only=True)
    refresh = serializers.CharField(read_only=True)

    def validate(self, attrs):
        data = super().validate(attrs)

        refresh = self.get_token(self.user)

        data['refresh'] = text_type(refresh)
        data['access'] = text_type(refresh.access_token)

        return data

I had to explicitly declare these two fields under class statement, otherwise I have been receiving:

KeyError: "Got KeyError when attempting to get a value for field email on serializer CustomTokenObtainPairSerializer.\nThe serializer field might be named incorrectly and not match any attribute or key on the dict instance.\nOriginal exception text was: 'email'."

TokenRefreshSlidingSerializer verifies exp claim when constructing SlidingToken

From the documentation in the readme:

Additionally, as long as the timestamp in its refresh expiration claim has not passed, it may also be submitted to a refresh view to get another copy of itself with a renewed expiration claim.

This documentation doesn't seem to match what is happening in the code. The expiration claim is being checked even though only the refresh claim should matter.

The TokenRefreshSlidingSerializer serializer creates an instance of SlidingToken and then checks the refresh claim expiry. The constructor of SlidingToken calls the __init__ method of Token which tries to verify the exp claim of the token and raises a 401 if it isn't valid.

As far as I can see, the SlidingToken constructor should be passed verify=False to avoid verifying the exp claim, since only the refresh claim should matter in this particular serializer.

Are there any other concerns with passing verify=False to the constructor?

IndexError: list index out of range

When sending empty string as a value of Authorization header, i.e: Authorization:, then I get:

  File "/usr/local/lib/python3.6/site-packages/rest_framework_simplejwt/authentication.py", line 35, in authenticate
    raw_token = self.get_raw_token(header)
  File "/usr/local/lib/python3.6/site-packages/rest_framework_simplejwt/authentication.py", line 69, in get_raw_token
    if parts[0] not in AUTH_HEADER_TYPE_BYTES:
IndexError: list index out of range

(this is only a bottom part of traceback)

I believe the code responsible for this behaviour is:

    def get_raw_token(self, header):
        """
        Extracts an unvalidated JSON web token from the given "Authorization"
        header value.
        """
        parts = header.split()

        if parts[0] not in AUTH_HEADER_TYPE_BYTES:
            # Assume the header does not contain a JSON web token
            return None

        if len(parts) != 2:
            raise AuthenticationFailed(
                _('Authorization header must contain two space-delimited values'),
                code='bad_authorization_header',
            )

        return parts[1]

I think this situation should be handled somehow, right now this will result in 5xx type response. Should I prepare PR to fix that, supposing that this is fault of this library and not my code (otherwise suggest what might be the cause in my code) ?

Access JWT claims in view method

Hello everyone,

I'm currently working on a DRF ViewSet which defines a create() method.

For this method i need to access the user_id claim from the JWT.
I couldn't find anything on accessing claims during view handling/preparing so I'm currently stuck with
a imo rather bad solution for this :

def create(self, request, *args, **kwargs):
    data = request.data
    jwt_token = request.META.get("header").split()[-1]
    user_id = jwt.decode(jwt_token, lc.SECRET_KEY, algorithm="HSA256")["user_id"]
    ... do more stuff ...

Is there any possibility to acces the claims within the method?
If not, are there any plans on creating such a utility?

Thanks in advance.

Invalid token response does not provide WWW-Authenticate header

According to RFC:

The server generating a 401 response MUST send a WWW-Authenticate header field (Section 4.1) containing at least one challenge applicable to the target resource.

I think 401 status code is used correctly here (403 applies to already authenticated user), so it would be nice for response to conform with RFC.

Refresh custom claims

Hi,

I switched from django-rest-framework-jwt to django-rest-framework-simplejwt.

  • I'm using a sliding token
  • I override TokenObtainSlidingSerializer get_token methods to add custom claims (first_name, last_name, ...)
  • Users can update some of these data in the app

Problem: refresh the token just update the exp value. Is there a way to refresh custom claims with fresh data too ?

Django 2.0 dropping support for Python 2

Unit tests against django master are failing because Django 3.0 is going to drop support for Python 2. They are deprecating django.utils.encoding.python_2_unicode_compatible function, which is imported and used as a decorator in models.py. This error can be see on the py37-djangomaster-drf39 test case:

INTERNALERROR>   File "/home/jnegro/PycharmProjects/django-rest-framework-simplejwt/rest_framework_simplejwt/models.py", line 5, in <module>
INTERNALERROR>     from django.utils.encoding import python_2_unicode_compatible
INTERNALERROR> ImportError: cannot import name 'python_2_unicode_compatible' from 'django.utils.encoding' (/home/jnegro/PycharmProjects/django-rest-framework-simplejwt/.tox/py37-djangomaster-drf39/lib/python3.7/site-packages/django/utils/encoding.py)

The link to the deprecation announcement is here:
https://github.com/django/django/blob/77d25dbd0f20d6a907c805ffae8aaadd87edbacf/docs/releases/3.0.txt#L277

The course to resolve this will most likely be dropping all Python 2 support and removing the function from models.py.

Add support for separate access and refresh tokens

Though RFC 7519 doesn't dictate the use of separate access and refresh tokens, having separate tokens in this way is a common pattern when utilizing JWT's in authentication systems. It provides advantages in certain situations, most notably when an authenticated web service wishes to keep a list of blacklisted (refresh) tokens but also wishes to avoid performing a database lookup against that list for every authenticated request. We should add support for this pattern and also potentially add blacklist functionality or pluggability.

Add option to provide blank AUTH_HEADER_TYPE?

Wondering what thoughts are on allowing an empty AUTH_HEADER_TYPE to the settings. I've seen some other packages that simply omit Bearer or Token from the Authenticate header when implementing JWT.

In my case, Swagger docs for django rest framework don't play nice with JWT yet, and allowing a blank AUTH_HEADER_TYPE would solve that issue.

It seems providing AUTH_HEADER_TYPE=None causes an encode error, and empty string doesn't authenticate correctly.

So far i'm loving this package, thanks!

Allow cookies support, so that SessionAuth won't be required for the DRF browsable API

Currently we often end up with a REST_FRAMEWORK config like this:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
        # I want to get rid of the next line but still be able to browse the API
        'rest_framework.authentication.SessionAuthentication',
    ),
}

Here rest_framework.authentication.SessionAuthentication is present in order to allow browsing DRF's browsable API, which relies on cookies. However, this session auth class often causes problems for the primary application (cross-site origin related, not to go into too many details).

If only there were an option for SimpleJWT to set and read cookies as well as headers, it would have saved the day.

Serializer responsability

I can see that serializers in this library are authenticating users. Does this break the Single Responsability Principle? In my project I want to pass the request object to the authentication method but as it is coupled with serialization I can not do it without rewriting the entire TokenObtainSerializer.

Running tests locally fails

Do you have some instructions on how to run the test. When i do pytest, test are collected but a lot of them fail. Probably you have to run them in a django installation?

output of pytest

Refresh token rotation not storing the valid one on Outstanding token table

Hi!

When 'ROTATE_REFRESH_TOKENS': True, and 'BLACKLIST_AFTER_ROTATION': True, the old refresh token is stored on the Blacklist table, but the new one delivered is not stored on the outstanding token table.

Is that the desired behaviour? Because by that way the new delivered refreshtoken cannot be manually blacklisted since we don't have it anywhere

Thank you for the lib!!

User Creation and Custom Responses

David, thanks for the great package.

I had a couple of issues I was running into that hopefully have an easy fix.

First was authenticating Users upon account creation. I tried implementing a serializer that inherited from TokenObtainPairSerializer.

class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super(MyTokenObtainPairSerializer, cls).get_token(user)
        access = token.access_token
        return token, access

Upon authentication, I would add the token to the payload I passed to the frontend. The problem with this function is that it returned a jti, expiration and token type, but the actual token always returned None.

The other issues I wanted to tackled was modifying the MyTokenObtainPair end point to include user information in the Response.

Thanks for the guidance.

Add support for Fernet tokens, also possibly rebrand library as general-purpose stateless token auth library

Add support for Fernet tokens. Also, consider rebranding django-rest-framework-simplejwt as a general purpose stateless token auth library which supports either JWT or Fernet.

The JWT specification has various problems in that it allows for crypto negotiation or even unsigned tokens. Fernet is an alternative signed token spec that has the advantages of being more explicit, simpler, and dictating encryption of token contents.

Fernet specification: https://github.com/fernet/spec/blob/master/Spec.md
Fernet implementation in Python "cryptography" library: https://cryptography.io/en/latest/fernet/

authentication decorators

Hello,

If I wanted to use simple function based views, which would be the recommended way to check authorization with the access token from within the request header? Is there any decorator or should I create some custom methods?

Thank you in advance!

UPDATE: I just added the rest_framework decorator @permission_classes([IsAuthenticated]) but I am not sure whether this is the right way because it doesn't use the authorization access token from the request header at all.

Support Private/Public key algorithms (RS256 etc)

Would be nice if it was supported out of the box.

For now I can do it by making my own backend and making sure the SECRET_KEY settings is a dict.

Here is the working backend I wrote:

from django.utils.translation import ugettext_lazy as _
from rest_framework_simplejwt.backends import TokenBackend
from rest_framework_simplejwt.exceptions import TokenBackendError
from rest_framework_simplejwt.utils import format_lazy


class RSAPyJWTBackend(TokenBackend):
    """Token backend for PyJWT with RSA public/private keys."""

    def __init__(self, secret, algorithm):
        """Constructor."""
        if algorithm != 'RS256':
            raise TokenBackendError(format_lazy(_("Unrecognized algorithm type '{}'"), algorithm))
        import jwt
        self.jwt = jwt
        self.InvalidTokenError = jwt.InvalidTokenError
        
        if 'public' not in secret or 'private' not in secret:
            raise TokenBackendError(_("Unrecognized secret structure."))
        self.secret_public = secret['public']
        self.secret_private = secret['private']
        self.algorithm = algorithm

    def encode(self, payload):
        """Return the encoded token."""
        token = self.jwt.encode(payload, self.secret_private, algorithm=self.algorithm)
        return token.decode('utf-8')

    def decode(self, token):
        """Do low level validation and return it's payload."""
        try:
            return self.jwt.decode(token, self.secret_public, algorithms=[self.algorithm])
        except self.InvalidTokenError:
            raise TokenBackendError(_('Token is invalid or expired'))

Modify SIGNING_KEY to accept function

Before going further, thanks for your work :).

For my application, I use a unique SIGNING_KEY per user to generate the tokens.
On the current version of the library SIGNING_KEY must be a string instead of a function depending of the user.
Do you have any plan to modify that in the future ?

Thanks in advance for your answer.

How can i give expiry time based on user role?

i tried giving exp time in payload like this

SUPERUSER_LIFETIME = timedelta(minutes=60)
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
@classmethod
def get_token(cls, user):
    token = super(MyTokenObtainPairSerializer, cls).get_token(user)
    if user.is_superuser:
        token.set_exp(lifetime=SUPERUSER_LIFETIME)
    return token
class MyTokenObtainPairView(TokenObtainPairView):
    serializer_class = MyTokenObtainPairSerializer

in urls.py:

     url(r'^api/token/$', MyTokenObtainPairView.as_view(), name='token_obtain_pair')

when i try to override get_token method refresh token expire time is getting overrided rather access_token.how can i override the expire time of access_token?

PyJWT

I may be a bit biased and curious, if you're only using a subset of the spec, why not use PyJWT instead of python-jose?

AttributeError when trying to access "is_staff" or "is_superuser" on a TokenUser

Bug Report

Expected behavior/code
If I have a JWT token with the "is_staff" or "is_superuser" property set, I expect these properties to be available on a TokenUser instanciated with this token.

Actual Behavior
A clear and concise description of the behavior.

Steps to Reproduce

token = AccessToken()
token.payload["is_staff"] = True
user = TokenUser(token)
user.is_staff

File "/usr/local/lib/python3.6/site-packages/rest_framework_simplejwt/models.py", line 47, in is_staff
return self.token.get('is_staff', False)
AttributeError: 'AccessToken' object has no attribute 'get'

Environment

  • python: 3.6.5
  • django: 2.0.8
  • djangorestframework: 3.8.2
  • djangorestframework_simplejwt: 3.2.3

Possible Solution
Poke the payload instead of the token itself:

@cached_property
def is_staff(self):
-     return self.token.get('is_staff', False)
+    return self.token.payload.get('is_staff', False)

@cached_property
def is_superuser(self):
-    return self.token.get('is_superuser', False)
+    return self.token.payload.get('is_superuser', False)

Custom token claim not in output

I'm trying to put out with the token a field that indicates that a user needs to change password.

So I implemented a custom claim, this way:

class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super(MyTokenObtainPairSerializer, cls).get_token(user)

        # Add custom claims
        token['chp'] = True
        # ...

        return token

class MyTokenObtainPairView(TokenObtainPairView):
    serializer_class = MyTokenObtainPairSerializer

I can see the debugger step in, then the token is returned, but when I make the api call the token still contains only access and refresh.

Error for TokenRefreshView, 403 Forbidden

  • Platforms:
  1. Python: 3.6.5
  2. Django: 2.0.3
  3. djangorestframework: 3.8.2
  4. djangorestframework-simplejwt: 3.2.3
  5. React
  • Description:

When it is required to refresh the access token with the TokenRefreshView view through the frontend functionality in ReactJs fetch () (general functionality in Javascript for request), it happens that it responds with 403 Forbidden: CSRF cookie not set.

With the obtaining of the token I do not have any problem, it is only with the refreshing; The headers that are sent to you are the following:

image

And the configuration of the headers for the fetch is the following:

export const refreshAccessToken = (token) => ({
  [RSAA]: {
    endpoint: 'api-auth/token/refresh/',
    method: 'POST',
    body: JSON.stringify({refresh: token}),
    headers: {
      'Accept':  'application/json',
      'Content-Type': 'application/json',
      'Cache': 'no-cache'
      // 'Cookie': document.cookie,
      // 'X-CSRFTOKEN': document.cookie.split('=')[1].split(';')[0]
    },
    'credentials': 'include',
    types: [
      TOKEN_REQUEST, TOKEN_RECEIVED, TOKEN_FAILURE
    ]
  }
})

I have tried to configure in different ways, from the simplest, only with the Content-type, to add those that are commented; I found a different answer when adding the X-CSRFTOKEN, I answer with error 405 Method Not Allowed.

PS: The method discussed in the code is equivalent to the fetch () but it really is of redux-api-middleware, I will be attentive to the updates of this error.

Token saved to OutstandingToken does not match custom serializer output

When a custom serializer adds extra fields to the JWT payload and the rest_framework_simplejwt.token_blacklist app has been added to INSTALLED_APPS in settings, the token field in OutstandingToken does not match that returned to the user.

The following 2 lines in the code are responsible for entering the string representation of the tokens into the database:
https://github.com/davesque/django-rest-framework-simplejwt/blob/master/rest_framework_simplejwt/tokens.py#L210
and
https://github.com/davesque/django-rest-framework-simplejwt/blob/master/rest_framework_simplejwt/tokens.py#L230

This does not directly influence any of the blacklisting functionality due to the fact that it uses the jti to decide if a token is valid, this is more a problem that could cause confusion due to the mismatch between the token in the database and the token given to the user.

So far I have not found a nice solution to this problem from an external stand point and it seems action will be required within this codebase to resolve this.

In my specific case I am only adding more user information to the JWT, so making the Token object swappable in django-rest-framework-simplejwt and overwriting the for_user method in my application could be sufficient. It may also remove the need for a custom serializer in this case.

Let me know your thoughts, I'm happy to contribute to the solution if needed.

Logout Functionality

How can i invalidate the token after the user logout form the application before token expire? Clearing the token form client side is not enough for prevent the access to protected resources. Is there any other options or work round for invalidate the key?

Revoke refresh token if password is changed

If the user changes his/her password, the old refresh token can still be used to generate new access tokens.

How to make refresh tokens invalid if username or password is changed

`state.token_backend` does not respect updated Django settings at test time

While writing a small integration test to assert that data can be retrieved from a JWT created by this lib, I found that pytest-django's settings fixture is not causing an update to state.token_backend instance (https://github.com/davesque/django-rest-framework-simplejwt/blob/128582df8f07b5e0fb74c51a0dc90d11302bba07/rest_framework_simplejwt/state.py#L9-L10).

Given a settings file with SECRET_KEY = '__SECRET_KEY__':

def test_default_is_secret(settings):
    result = settings.SECRET_KEY

    assert result == '__SECRET_KEY__'

Then when the SIMPLE_JWT.SIGNING_KEY value is updated, this test passes:

def test_settings_not_updated(api_client, url, user, settings):
    """
    When settings are updated using pytest's settings fixture, the
    ``state.token_backend`` instance has already been created with the old
    value of the setting and is not updated.
    """
    settings.SIMPLE_JWT = {
        'SIGNING_KEY': '__SIGNING_KEY__',
    }
    data = {
        'username': 'a_user',
        'password': '__PASSWORD__',
    }

    result = api_client.post(url, data=data)

    assert result.status_code == 200
    assert sorted(result.data) == ['access', 'refresh']
    jwt.decode(result.data['access'], key='__SECRET_KEY__', algorithms=['HS256'])

This test should fail because the call to jwt.decode is using key='__SECRET_KEY__', which is the "old" value - it should be key='__SIGNING_KEY__' as per the updated setting.

As per encode/django-rest-framework#2466, there is now the reload_api_settings() fn in DRF and that is used in this lib too. I have hooked into it and checked that it is definitely being called when the settings fixture is changing the settings. However, it appears to me that it's too late to update token_backend which is created at load time.

My experience here is probably just an edge case, but if a fix is on the cards, then my suggestion would be to change token_backend from being statically created to using some kind of function like get_token_backend() to generate the TokenBackend instance when required rather when loaded.

Custom fields are not being added.

Extra fields are not being added. I was following the documentation https://github.com/davesque/django-rest-framework-simplejwt#customizing-token-claims

class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
   @classmethod
   def get_token(cls, user):
       token = super(CustomTokenObtainPairSerializer, cls).get_token(user)

       token['username'] = user.username
       token['id'] = user.id
       return token


class CustomTokenObtainPairView(TokenObtainPairView):
   serializer_class = CustomTokenObtainPairSerializer

url

 re_path(r'^token/obtain/$', views.CustomTokenObtainPairView.as_view()),

I have tried editing the source code and values have changed. I'm using django 2.0.5 and python 3.5.2

Add ValidationView

For the HS256 algorithm it would be nice to have a view that you can pass a token and it returns if it's valid or not. For when you don't want to hand out your secret but still want to offer a way to validate the token.

Use default_error_messages and self.fail

Let's take a look at TokenObtainSerializer:

class TokenObtainSerializer(serializers.Serializer):
    username_field = User.USERNAME_FIELD

    def __init__(self, *args, **kwargs):
        super(TokenObtainSerializer, self).__init__(*args, **kwargs)

        self.fields[self.username_field] = serializers.CharField()
        self.fields['password'] = PasswordField()

    def validate(self, attrs):
        self.user = authenticate(**{
            self.username_field: attrs[self.username_field],
            'password': attrs['password'],
        })

        if self.user is None or not self.user.is_active:
            raise serializers.ValidationError(
                _('No active account found with the given credentials'),
            )

        return {}

And let's change this and other serializers to look more like that:

class TokenObtainSerializer(serializers.Serializer):
    default_error_messages = {
        'incorrent_credentials': _('No active account found with the given credentials')
    }

    username_field = User.USERNAME_FIELD

    def __init__(self, *args, **kwargs):
        super(TokenObtainSerializer, self).__init__(*args, **kwargs)

        self.fields[self.username_field] = serializers.CharField()
        self.fields['password'] = PasswordField()

    def validate(self, attrs):
        self.user = authenticate(**{
            self.username_field: attrs[self.username_field],
            'password': attrs['password'],
        })

        if self.user is None or not self.user.is_active:
            self.fail('incorrect_credentials')

        return {}

This way, when I inherit over TokenObtainSerializer and override validate method, I don't have to copy and paste the error message, I can just use self.fail with proper argument. What do you think?

Allow httpOnly cookie storage

Similar to #23 but with a different motivation.

To protect against XSS, I would like the option to store the JWT in an HttpOnly cookie. django-rest-framework-jwt has this feature as an optional setting but that project I believe is abandoned and also has a vulnerability due to preventing the usage of django's CSRF token (see: jpadilla/django-rest-framework-jwt#434). Combining an HttpOnly cookie with CSRF token would be a pretty rock solid solution.

References:
https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage
https://stackoverflow.com/questions/44133536/is-it-safe-to-store-a-jwt-in-localstorage-with-reactjs

ImportError: cannot import name 'InvalidTokenError'.

I am getting this error:

ImportError: Could not import 'rest_framework_simplejwt.authentication.JWTAuthentication' for 
API setting 'DEFAULT_AUTHENTICATION_CLASSES'. ImportError: cannot import name 
'InvalidTokenError'.

image

any idea why?

Allow multiple algorithms to be used

We need to allow both RS256 and HS256 authentication. Basically we want to allow users of our API to either login with email/password to get the the token (normal users), or, they provide us their public key to verify their secret key signed JWT signature (external systems using our API). At the moment, drf simplejwt does not seem to allow this without some hacking.

Currently the Token class' __init__ does the following:

# An encoded token was provided
from .state import token_backend

# Decode token
try:
    self.payload = token_backend.decode(token, verify=verify)
 except TokenBackendError:
    raise TokenError(_('Token is invalid or expired'))

Could it instead do something like token_backend = self.get_token_backend() to fetch the backend? This way we could create tokens for different backends (with different algorithms) without having to copy paste the whole init function. This may not be the most elegant way to solve this, as it will still be bit weird to have the single ALGORITHM setting, if multiple could be used.

A suggestion to prevent AttributeError when accessing TokenUser.is_superuser

Thanks for the really nice ideas implemented in this module. I am in the process evaluating this package to implement SSO. I encountered AttributeError: 'AccessToken' object has no attribute 'get' while calling TokenUser.is_superuser.

I have diagnosed that the exception is due to the lack of a get() method implemented in the Token class.

Adding this piece of code should fix the issue.

    def get(self, key, default=None):
        return self.payload.get(key, default)

cheers

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.