User Authentication is a simple concept, but when it comes to properly implementing it in Django, things can get complicated. Django offers an abundance of different authentication mechanisms: BasicAuthentication, TokenAuthentication, SessionAuthentication, and various ways to implement custom authentication mechanisms.

The introduction of Django REST Framework did great things for Django. However, it introduces another layer of confusion, and often leaves the developer asking “Which authentication mechanism should I use?”
If you’re building a web app backed by a Django REST Framework API, and that web app needs to handle user authentication, then you probably have the following requirements for user authentication:

  • Users must be able to authenticate with the API using a username and password.
  • Authentication with the API should return a token for future requests.
  • Authentication tokens should expire after a set amount of time.
  • Users should be able to refresh their token with an API request.
  • Users should be able to change their passwords.

These seem like simple requirements, but none of the built-in authentication mechanisms fully satisfy these needs, or lack the necessary amount of security. In this article, I’m going to show you what has become my favorite way of getting user authentication working in my web apps. It’s a great little solution for web apps that have to manage user sessions.

I’ll assume that you already have a working Django REST Framework project for this tutorial. If you don’t check out my series on starting a new Django REST Framework project.

Setting Up User Authentication and Registration

django-rest-auth is a great little package which encompasses almost everything you need to get user authentication up and running in your API. On it’s own, it fulfills a majority of the requirements I outlined above.

What Modifications Do We Need to Make?

To fulfill our needs, we’re going to also configure django-rest-auth’s optional registration app. This will allow us to easily register new user accounts without any custom code on our part.

By default, django-rest-auth uses standard Django tokens to allow users to authenticate. However, these tokens never change. So we’re also going to configure django-rest-auth to use django-rest-framework-jwt: a package providing a secure JWT implementation. These tokens can be configured to expire after a set amount of time, which is much more secure than the default token implementation.


To get started, let’s install the three packages we’ll be using.

pip install django-rest-auth
pip install djangorestframework-jwt
pip install django-allauth

Configure the Django Settings

Now that we have our packages installed, add the following apps to your settings file.


At this point, the django-rest-auth tutorial would also tell you to add the rest_framework.authtoken app as well. However, since we’re going to use JWTs, we don’t need to do this.

To use JSON Web Tokens (JWTs), we’ll have to also add the following configuration settings:

import datetime

# Configure the JWTs to expire after 1 hour, and allow users to refresh near-expiration tokens
    'JWT_EXPIRATION_DELTA': datetime.timedelta(hours=1),

# Make JWT Auth the default authentication mechanism for Django

# Enables django-rest-auth to use JWT tokens instead of regular tokens.

To make the registration app work, we’ll also have to add the following setting, which is required for the django.contrib.sites dependency.


That’s all the setting changes that we’ll need to start adding our views.

Adding our Views

Django-rest-auth and django-rest-framework-jwt provide a few views for us that we can enable in our api.

Add the following to your  file to enable login, logout, and registration (and the rest of the django-rest-auth endpoints listed here).

urlpatterns = [
    url(r'^rest-auth/', include('rest_auth.urls')),
    url(r'^rest-auth/registration/', include('rest_auth.registration.urls'))

There’s still one more thing we’ll have to do if we want to allow users to refresh their tokens without logging in again. django-rest-framework-jwt has a view we can include which will do just this. Add the refresh_jwt_token view to your urls as shown below.

from rest_framework_jwt.views import refresh_jwt_token

urlpatterns = [
    url(r'^rest-auth/', include('rest_auth.urls')),
    url(r'^rest-auth/registration/', include('rest_auth.registration.urls')),
    url(r'^refresh-token/', refresh_jwt_token),

Now we’re done! Run python migrate to make all the necessary database changes, and then you will be able to start using these.

Testing our Views

Now that the heavy lifting is done, I could end this blog post. A lot of people probably would. I mean, I told you everything you need to know to get this working, right?


Now I’m going to show you how to actually use the API we just built. In my opinion, nothing is worse than knowing exactly how to configure something to work, and then not knowing how to use it.

When I’m doing this type of testing, I usually use an app called Postman. I’d recommend getting that, but you could also make these HTTP requests on the command line using a tool like cURL.

Below, I’ll give you the endpoint, method, and payload for each action we want to perform. You can plug this information into Postman or use it in an AJAX request in your code to use them.


Method: POST
Endpoint: /rest-auth/registration/

    "username": "USERNAME",
    "password1": "PASSWORD",
    "password2": "PASSWORD",
    "email": "OPTIONAL_EMAIL"


Method: POST
Endpoint: /rest-auth/login/

    "username": "USERNAME",
    "password": "PASSWORD"


Method: POST
Endpoint: /rest-auth/logout/
Headers: Authorization: JWT YOUR_TOKEN_HERE

Refresh Token

Method: POST
Endpoint: /refresh-token/

    "token": "YOUR_OLD_TOKEN"

That’s it, use Postman, curl, or another tool to build requests based on the above descriptions and you’ll be all set!

Web app development is slowly trending towards having a separate UI and API.  With that, comes a different need for user authentication. I hope this tutorial helps you fulfill that need the best way possible.

Let me know if you have any questions or suggestions in the comments below! Stay tuned for a blog post on API key authentication, for those of you creating RESTful web services.

Recommended Posts


  1. Correction for code line 2 of “Installation”. django-rest-framework-jwt is actually djangorestframework-jwt

    • Hi first thaks for the tutorial, I have a problem with the confirmation email, when I test the api(http://localhost:8000/rest-auth/registration/) with postman I recive a confirmation email, but when I try to confirm the email using the link that I recive in the email I have an error like this

      “ImproperlyConfigured at /rest-auth/registration/account-confirm-email/Mw:1fIdXY:fJ8VjWwzFUGvdakFPA723w47MJo/
      TemplateResponseMixin requires either a definition of ‘template_name’ or an implementation of ‘get_template_names()'”

      I wonder if Could you help me with that

      • Same problem for me

  2. Hey Michael, thanks for this article!
    I’m looking for a way to integrate social authentication to my Django + DRF app and I’m a bit lost.
    I used Django allauth in the past and seems the most widely used app for social auth but it seems not to support ajax interaction out of the box. Do you have any experience or clue about how to tackle this problem?
    Thank you very much!

    • Hey there, django-rest-auth (the same package I used in this tutorial) uses django-allauth under the hood, and provides endpoints for social authentication. You can get it working by following this tutorial, and also doing the optional social auth configuration mentioned here. Then, you’ll be able to use django-rest-auth’s endpoints to authenticate with Facebook and Twitter (see here). If you need more social networks than that, you can include additional allauth provider apps in your INSTALLED_APPS (see here for all the possible providers). I hope that helps, thanks for reading!

      • Hey Michael, thank you so much for your soon answer. I’m going to follow the links and try to get it to work.
        You save me a lot of work and research, thanks again!
        (FWI: I found your article through the LinkedIn Django group)

  3. Cheers for the solution Michael, I have two issues though.
    1. Your payloads contain some odd ” quotes, so I search-and-replaced them with standard ” quotes and it worked fine afterwards.
    2. I tried all the payloads and they seem to work fine except for the logout. Django returns 403 with a following message: { "detail": "CSRF Failed: CSRF cookie not set." }. How should I go about sending that cookie to Postman to be able to set it in the header as X-CSRFToken?

    • Hey there, thanks for catching those odd quotes.. I’m not sure how that happened! Regarding your second item, I believe this is because you still have SessionAuthentication enabled in your settings. Is that true? If so, try removing it and see if the CSRF error stops. Let me know if that works!

      • Yes, it worked! Thanks for the quick reply, Michael! Also, cheers for the tips on how to write better Python code.

        For anyone in the future, this is how my REST_FRAMEWORK config looks like:

        REST_FRAMEWORK = {
        • You’re very welcome! If you did find this (or other articles useful) please share them with others!

  4. Hello Michael, I have implemented everything as you have mentioned above but I’m getting this error- ImportError: cannot import name ‘LoginView’. I’m using Django version 1.11.7 What can be the solution for this?

    • Hey there Dixon. I believe the login view is used when using SessionAuthentication. My best guess is that you are trying to import the login view in your URLs file, but don’t have the proper settings in your

  5. Hey, thanks for the tutorial! 😀 I particularly appreciate your explanation in regard to the choice of jwt and why to remove rest_framework.authtoken from the django-rest-auth tutorial.


    I am trying to test with a curl call:
    curl –request POST \
    –url \
    –header ‘content-type: application/json’ \
    –data ‘{“username”: “USERNAME”, “password”: “PASSWORD”}’

    And then get this error message:
    {“non_field_errors”:[“Unable to log in with provided credentials.”]}%

    I was a little unclear what exactly to use for the curl call/postman parts…Does this look feasible or am I missing something?

    PS Merry Christmas!

    • Nevermind — there error’s source was completely unrelated to the content here.

      Again, thanks for the wonderful tutorial!!

  6. Hi,

    Thanks for the tutorial. Not sure if it’s because I’m using Django 2.0, but I got this error while trying to send a GET request:

    ‘JSONWebTokenAuthentication’ object has no attribute ‘has_permission’

    Do you know if it’s because some new changes in ‘rest_framework_jwt’ itself?

    Thank you very much.

    • Hey there, thanks for reading! The django-rest-framework-jwt docs say that they only support up to Django 1.10. It’s very possible that an incompatibility is causing this. However, without seeing more of your implementation it’s hard to say! Let me know what you find out. Try the same code in a Django 1.10 app and compare your results! If there is an incompatibility, maybe we can submit a patch.

  7. Hi bro¡ I have many questions. I followed the tutorial but i did not find how to implement that in my view’s permission_classes. I apreciate if someone can help me. (sorry for my english I’m not native)

    • Hi Klaus, are you trying to implement custom permission classes? The predefined classes can be set on your view by setting the class’s `permission_classes` variable. See here.

  8. Really great tutorial.

    Just a question. It seems the line url(r’^’, include(‘rest_auth.urls’)) is overriding the original url(r’^’, include(router.urls)). This disables all routes other than auth’s disbaled, thus, 404.

  9. Also, would like to know why the homepage suddenly displays an error:

    ‘JSONWebTokenAuthentication’ object has no attribute ‘has_permission’

    I believe it is due to me overriding the default api_root:
    url(r’^$’, api_root),
    def api_root(request, format=None):
    return Response({
    ‘users’: reverse(‘user-list’, request=request, format=format),
    ‘groups’: reverse(‘group-list’, request=request, format=format),


  10. For people creating custom API on the basis of this post and wondering how to pass token for API calls –
    please put token in header just like how Author described it for Logout API –

    Authorization: JWT your_token_here

    I would like to request the Author to mention this fact in the post because users would be interested in using the Token for APIs other than authentication too 🙂

    • Hey Divyanshu, thanks for the reply. My full intention here is for the JWT token to be passed as the Authorization header for all API requests. I should have been more clear on that. Thanks for pointing out the fact that you can (and should) be doing this!

      • Very nice post! There’s something I can’t find anywhere, how do you manage when a user changes his password or user gets deleted/deactivated? Is there a way to force a token regeneration in that case, or maybe passing through the header everytime emai/psw to check credentials are still valid?

        Thank you!

        • Hey Fabio. I rely on the django-rest-auth endpoints to reset passwords. I’m not positive if they have functionality to delete/deactivate users though. Regarding tokens, the django-rest-framework-jwt package has means of regenerating tokens.

  11. Thanks, Michael, this is awesome tutorial, it would be nice if you would have some tutorial about how to use custom fields…for example I am a newbie to Django, and i even don’t know where to start …

    • Hey Matt, thanks for reading. Are you talking about custom fields for users? For example, recording a second email for a user. If so, I typically just make a new model with a one-to-one relationship with the default django user model. I’ll consider doing a quick tutorial on this fully explaining the process. Thanks for the suggestion!

      • Thanks for the reply Michael!
        I was talking about additional fields for a user, let’s say for example I want to force a user to add additional required fields during registration like first name, last name, and age. And make an email and last name as required fields for logging in.
        I think a lot of people would like to make some custom modifications, and there is literally no tutorial for that on the internet, except just pieces of info here and there on StackOverflow.

        • I second Matt! I made a separate model with a one-to-one relationship to User but I can’t figure out how to include and require those fields (as Matt mentioned) in the registration, and how to make sure both models, the user and the new model, are created when registrating. I saw several ways to do that (like signals) but a full explanation in regards to authentication using this third-party package (or another one lie Djoser) would be highly appreciated.

      • I second Matt! I made a separate model with a one-to-one relationship to User but I can’t figure out how to include and require those fields (as Matt mentioned) in the registration, and how to make sure both models, the user and the new model, are created when registrating. I saw several ways to do that (like signals) but a full explanation in regards to authentication using this third-party package (or another one lie Djoser) would be highly appreciated.

  12. hi nice tutorial, simple and easy to follow, but i get this error ConnectionRefusedError: [Errno 111] Connection refused with Register i tink is someting to do with sending an email how i can fix this ??? sorry about my english not my first language

  13. Hi Micheal,

    Great tutorial, glad i stumbled upon it.

    I am currently trying to send a POST request to my local server and i keep getting a 400 with this JSON object as the response:

    ‘{“username”:[“This field is required.”],”password1″:[“This field is required.”],”password2″:[“This field is required.”]}’

    I passed the 3 required parameters and I still get the error, I tried re-installing all my packages and double checked all my urls, do you have an idea of whats causing this.

    Thank you,


  14. http POST {“username”:”test”,”password1″:”test@123″,”password2″:”test@123″,”email”:””}
    HTTP/1.1 400 Bad Request
    Allow: POST, OPTIONS
    Content-Length: 120
    Content-Type: application/json
    Date: Mon, 26 Feb 2018 11:37:06 GMT
    Server: WSGIServer/0.2 CPython/3.6.4
    Vary: Accept
    X-Frame-Options: SAMEORIGIN

    “password1”: [
    “This field is required.”
    “password2”: [
    “This field is required.”
    “username”: [
    “This field is required.”

    Hi Michael,
    I did everything as mentioned but I am getting the error mentioned above.

    Here are my installed apps:

  15. Hi Dear Michael
    Thanks for nice Tutarial

    i have a problem, i want to use my own table, but rest_auth build (auth_user).
    how to add other field in rest_auth ?

  16. Awesome tutorial Michael!

    This setup is requiring a token on every call. Is there a way to exclude some calls? Reason I need this is that the CORS preflight OPTIONS call sent automatically by the browser is getting a 401 because it doesn’t have the token header and there’s no way to add it.

    HELP!!! 🙂

    Thank you!


    • That is odd. I haven’t had that problem with the preflight OPTIONS call requiring authentication. Are you sure something hasn’t been mis-configured along the way?

  17. I was able to get this working for registration and login and I’m get my JWT tokens everything works great. Is it possible to use the social account registration/login of test/auth to also with the drf JWT

    • Yes, the two authentication methods should work nicely along side eachother. Simple configure them both according to the docs here and then the social authentication endpoints should also return JWTs. Let me know if that helps

  18. Hi Michael

    Thanks for your article! I’m wondering if one can do the authentication via SSL certificate.
    Do you know how to do it?

    • Hey Arash, I don’t believe Django-Rest-Auth supports certificate-based authentication out-of-the-box. But you could always inherit from the base authentication class and implement your own method. This is something I’ve never had to do before. Best of luck!

  19. Hi Michael! Thanks for the blog. I am using JWT and I wanna know if and how I can persist session data on the server side using this. Let’s say I login in and the server sends the token after authentication, the client stores it and sends it as part of the header for authorization.From login until logout, one can say that its a single user session and in that case how can I maintain the session data on the server side by retrieving the token.Also, how do I do that if the token is refreshed in between login and logout?

  20. The default logout endpoint seems to do nothing except return that the user has logged out. If you take your token and try another GET request with it after logging out, it works just fine. I’m not sure if I forget a step, or you forget a step, or there’s an issue with the JWT integration. Any ideas?

  21. Thanks for this tutorial. I’ve been able to get everything working through Postman, but I can’t get a GET request working through the python requests library. Part of my problem is I don’t really understand how Postman is implementing the authentication.

    In particular, when I try to use the requests module, I have something like:
    import requests
    reqauth =, data={‘username’:’name’, ‘password’:’pword’)

    this works and gives me a token

    But when I try to use the token:
    auth = {‘Authorization’: ‘JWT’ + very_long_token}
    requse = requests.get(urluse, headers=auth)

    I get a 403 status code, with json:
    {‘detail’: ‘Authentication credentials were not provided.’}

    I’m fairly new to this, so I may be doing something stupid, any help is appreciated immensely!

    • In rereading the above I had left off the space after ‘JWT’, but in my actual code I did it properly ‘JWT ‘ + …

      I also tried using ‘Bearer’ and ‘Token’ in place of ‘JWT’, but neither of those worked either…

      Thanks very much!

  22. Hi Michael I have sent you a request from your contact form regarding the issue with the same context please review it and help me out…thanks!

  23. Really good explanation, thanks!

  24. Greetings!

    Many thanks for your tutorial, it is priceless for development of a prototype SPA+DRF solution I’m currently doing. I had the same problem as Victor Lv4: Connection Refused, Errno 111. I solved it as you advised, by adding EMAIL_BACKEND option in settings.

    However, I’m still completely clueless WHAT was the actual problem, and WHY should I solve it like that? Although being seasoned programmer (mostly on MS stack), i’m quite new in Python and Django, and I simply could not understand those “what” and “why” I’m asking in this message, even after few hours of examining source code.

    So, can you elaborate, please?

    • Hey there Slaven. I believe the error is saying “Connection Refused”, because it is trying to connect to an SMTP server with the default django settings, pointing it to “localhost” and the default SMTP port number. Since there is no SMTP server running, it’s unable to connect, and therefore you receive a “Connection Refused” error. By correctly configuring the EMAIL_BACKEND setting to use the console backend, we can simulate a valid connection. In a production environment, we would want to configure this to use a valid SMTP server through a service like Gmail or Office 365.

      • A-ha! Okay, while obligatory SMTP connection might sound like an overhead, especially when one investigates some basic functionalities, in production reality there WILL be need for automated e-mails, so DRF/django-rest-auth simply do not consider SMTP connection as an overhead, but as an obligation that can be “mocked” for development purposes.
        Thanks for your answer.

  25. Looks great. But I also need to override the method to make sure the refresh token is only done once? Is it possible? Do you know how I can do that with django rest framework?

  26. Thanks for the great tutorial

  27. Thanks a lot man! I’m a beginner and you just saved my life! Cheers!

  28. pls, i have problem with my login api, i found out that only the super admin can login with the api, the register api works fine. I’m using AbstractBaseUser, pls i need help

Add a Comment

Your email address will not be published. Required fields are marked *