Search code examples
pythonangularjsdjangodjango-rest-frameworkdjango-rest-auth

Django + DRF + Angular: app renders JSON response from auth package instead of redirecting


I'm working on a webapp with Django backend, AngularJS frontend, and a Django REST Framework (DRF) API for the frontend to consume. I've posted a couple other questions about how to handle authentication in this sort of setup, but I think I've figured out generally how to go about it. I'm using the django-rest-auth package and realized I could simply change the form action in the provided login.html template to point at one of the django-rest-auth endpoints. Here's what the login form looks like:

<div class="container">
   <section id="loginForm">
        <form action="/rest-auth/login/?format=json" method="post" class="signin_form" style="font-weight: 400; font-style: normal">
            {% csrf_token %}
            <h1 class="sports_blue">SIGN IN</h1>
                <label for="id_username" class="sr-only control-label">User name</label>
                {{ form.username }}
                <label for="id_password" class="sr-only control-label">Password</label>
                {{ form.password }}
                <input type="hidden" name="next" value="/dashboard" />
                <div class="checkbox">
                    <label>
                        <input type="checkbox" value="remember-me"> Remember me
                    </label>
                </div>
                <input type="submit" value="Sign In" class="btn btn-primary btn-block" />

            {% if form.errors %}
            <p class="validation-summary-errors">Please enter a correct user name and password.</p>
            {% endif %}
            <br />
            <p><b>Don't have an account?</b> <a><b>Sign up for free!</b></a></p>
        </form>
    </section>
   </div>

This hits the auth endpoint and successfully logs in just fine, however instead of rendering the /dashboard specified in next, the JSON response (either the user's token or an error) is displayed.

I'm thinking this is because the vanilla Django auth backend doesn't return pure JSON, but I'm not sure how to have the next page rendered. Should I be using a different template? Or do I need to make other changes in my configuration to completely remove the basic Django authentication? I still have the auth middleware in place in settings.py:

MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
# Uncomment the next line for simple clickjacking protection:
# 'django.middleware.clickjacking.XFrameOptionsMiddleware',
) 

I know the django-rest-auth authors also have an angular module for this purpose, however it hasn't been updated in over a year, so I'm not sure if it would be appropriate to use. Is there some way that I should contain the login entirely on the frontend instead of using the template mentioned above?


Solution

  • The login.html is a usual Django template so it doesn't seem like you're using Angular for login page. What django-rest-auth provides is a handful of API endpoints for authentication purpose, that return JSON.

    You're trying to do a POST from browser in foreground mode (non-AJAX), so browser shows you whatever that view returns - JSON. Endpoint does not take to account ?next.

    This app assumes that you're using Angular or other SPA, that would POST using AJAX to these endpoints and implement redirects to ?next and other features in Javascript. But not using API endpoint in <form> inside Django template.

    Couple of options:

    • Implement auth views in Angular, that would use django-rest-auth endpoints. Or use boilerplate projects.

    • Use Django page, but point <form> to either Django's default login view or a custom regular Django view that is not an API endpoint but returns text/html or redirects to ?next.