# User not logging in with Custom Authentication Backend

**URL:** <https://forum.djangoproject.com/t/user-not-logging-in-with-custom-authentication-backend/28328>\
**Category:** Forms & APIs\
**Created:** [February 22, 2024, 3:45pm UTC](https://forum.djangoproject.com/t/user-not-logging-in-with-custom-authentication-backend/28328 "2024-02-22T15:45:14Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![andrew-kyle92](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/andrew-kyle92/32/19373_2.png) [@andrew-kyle92](https://forum.djangoproject.com/u/andrew-kyle92)\
**Post date:** [February 22, 2024, 3:45pm UTC](https://forum.djangoproject.com/t/user-not-logging-in-with-custom-authentication-backend/28328/1 "2024-02-22T15:45:14Z")

</div>

I’ve built an app that uses a custom authentication backend because I needed to integrate ldap. It works when authenticating into the admin console, but doesn’t on my app.

**The issue**  
After hitting the submit button on the login page, I am redirected back to the login page even if the authentication was successful.

**My troubleshooting**

- I am implementing class-based views and using the LoginRequiredMixin. I thought this was causing a redirection loop back to login, so I removed it. I’m no longer being redirected back to login, but using {{ user.is\_authenticated }} within my index page tells me that the user isn’t being “logged in”. I found that this wasn’t the cause so I added the mixin back in.

- I’ve double-checked the methods within the custom backend to ensure they’re working like Django’s backend, but haven’t seen any errors.

- I’ve also found that request.user returns Anonymous User, but within the request.session, the \_auth\_user\_id returns the authenticated user. It seems like there’s a disconnect between the request user and auth user.

Please let me know what information you need to help me troubleshoot.

Thank you!

Custom Backend Code

```auto
class LDAPAuthBackend(BaseBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        # will validate if the user exists in ldap
        user_exists = ldap.check_user_exists(username, "username")
        if user_exists[0]:
            user = None
            domain = user_exists[1]
            # checking to see if the user exists in the database, if not, create them
            try:
                user = User.objects.get(username=username)
                ldap_data = ldap.ldap_login(username, password, domain)
                if not ldap_data[0]:
                    return None
                return user
            except User.DoesNotExist:
                # create a new user if they authenticate
                # getting ldap data to create them in the system
                ldap_data = ldap.ldap_login(username, password, user_exists[1])
                if ldap_data[0]:
                    user_data = ldap_data[1]
                    user = User(
                        username=user_data["username"],
                        email=user_data["email"],
                        first_name=user_data["first_name"],
                        last_name=user_data["last_name"],
                        is_staff=True,
                        is_superuser=True if user_data["username"].lower() in settings.WEB_STAFF else False
                    )
                    user.set_unusable_password()
                    user.save()
                    return user
        return None

    def get_user(self, user_id):
        try:
            return User.objects.get(id=user_id)
        except ObjectDoesNotExist:
            return None

```

Login View Code

```auto
class UserLogin(View):
    title = "Login "
    template = "ipa/user-login.html"

    def get(self, request):
        print(request.user)
        if request.user.is_authenticated:
            return redirect("index")
        else:
            form = CustomLoginForm()
            context = {
                "title": self.title,
                "form": form,
                "next": request.GET.get("next"),
            }
            return render(request, self.template, context)

    def post(self, request):
        form = CustomLoginForm(request.POST)
        if form.is_valid():
            username = form.cleaned_data.get("username")
            password = form.cleaned_data.get("password")
            # authenticate user
            user = ldap.authenticate(self.request, username=username, password=password)
            # user = authenticate(self.request, username=username, password=password)
            # login user
            if user is not None and user.is_active:
                login(self.request, user, backend="core.backends.LDAPBackend")
                index_urls = ["/", "/ipa/"]
                redirect_to = request.GET.get("next") if request.GET.get("next") not in index_urls and not None else "index"
                if redirect_to == "None":
                    redirect_to = "index"
                print(request.user.is_authenticated)
                return redirect(redirect_to)
                # return HttpResponseRedirect(reverse_lazy('index'))
            else:
                messages.add_message(request, messages.ERROR, "Username or password is incorrect\nUse Active directory credentials.")
                return redirect("login")

```

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [February 22, 2024, 5:17pm UTC](https://forum.djangoproject.com/t/user-not-logging-in-with-custom-authentication-backend/28328/2 "2024-02-22T17:17:39Z")

</div>

For situations like this, particularly when you are working with remote resources, debugging generally involves either using a debugger, or adding in a _bunch_ of print statements to see what the data is that you’re sending, receiving, or using at every step along the way.

For example, in your authenticate method, I’d print `user_exists` after the `ldap.check_user_exists` call. I’d print `user` after the `User.objects.get`, then `ldap_data` after `ldap.ldap_login`, etc, etc, etc.

Another thing you could try would be to use the Django shell to manually execute these functions to be able to examine the responses.

There are many things that _could_ be wrong. You may not be sending the data in the exact format expected, or not getting back what you think you’re going to get. Finding the real issue here is likely going to require that you keep digging until you find the cause.

Side note: I question the accuracy of this expression:

> [@andrew-kyle92](#):
>
> `request.GET.get("next") if request.GET.get("next") not in index_urls and not None else "index"`

Since `not x` is of [higher precedence](https://docs.python.org/3/reference/expressions.html#operator-precedence) than `and`, I believe this gets parsed as:

```auto
request.GET.get("next") 
  if (request.GET.get("next") not in index_urls)
     and 
     (not None) 
else "index"`

```

The expression `not None` is always going to be True, so I’m not sure what you’re trying to test here.

---

<div class="post-metadata">

**Author:** ![andrew-kyle92](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/andrew-kyle92/32/19373_2.png) [@andrew-kyle92](https://forum.djangoproject.com/u/andrew-kyle92)\
**Post date:** [February 22, 2024, 5:27pm UTC](https://forum.djangoproject.com/t/user-not-logging-in-with-custom-authentication-backend/28328/3 "2024-02-22T17:27:32Z")

</div>

About the side note - You’re right with that logic. I will remove this and ensure the next parameter is always set to a valid url name. I need to revisit the logic of what I’m trying to achieve there.

I’m using pycharm; with that, I’m using their debugger which allows me to evaluate all objects in the current session. I see that after the login, within the post method, request.user.is\_authenticated returns True. Somewhere within the redirect, I feel like a new session is being created.

I’ve tried following the logic of how the redirect functions but have yet to see why/how the sessions are either being carried onto the next request or re-created.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [February 22, 2024, 6:09pm UTC](https://forum.djangoproject.com/t/user-not-logging-in-with-custom-authentication-backend/28328/4 "2024-02-22T18:09:47Z")

</div>

There appear to be two different situations here.

If the browser has a session id for an existing, authenticated, user, then the login function is going to create a new session id and delete the old one. (See the `login` function in `django.contrib.auth. __init__ `) This new sessionid cookie should be sent to the browser in the response sent after being logged in.

If the browser is currently without an authenticated sessionid, then it appears to keep that same session.

I’d probably want to look at the cookies being exchanged between the browser and the server for each exchange to see if the cookie is being dropped somewhere in between.

---

<div class="post-metadata">

**Author:** ![andrew-kyle92](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/andrew-kyle92/32/19373_2.png) [@andrew-kyle92](https://forum.djangoproject.com/u/andrew-kyle92)\
**Post date:** [February 22, 2024, 11:00pm UTC](https://forum.djangoproject.com/t/user-not-logging-in-with-custom-authentication-backend/28328/5 "2024-02-22T23:00:22Z")

</div>

Update on the issue. The authentication process is now functioning. Here’s what I did to resolve the steps. Although it is working, I still don’t know why this works versus my other method.

I set my UserLogin view to inherit the LoginView class from django.contrib.auth.views. I also changed my login form to inhert AuthenticationForm from django.contrib.auth.forms.

I changed the context of my view to this:

```auto
class UserLogin(LoginView):
    title = "Login"
    template_name = "ipa/user-login.html"
    authentication_form = CustomLoginForm

    @method_decorator(sensitive_post_parameters())
    @method_decorator(csrf_protect)
    @method_decorator(never_cache)
    def dispatch(self, request, *args, **kwargs):
        return super(UserLogin, self).dispatch(request, *args, **kwargs)

```

---

<div class="post-metadata">

**Author:** ![BishalTx](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/bishaltx/32/19074_2.png) [@BishalTx](https://forum.djangoproject.com/u/BishalTx)\
**Post date:** [February 27, 2024, 7:08pm UTC](https://forum.djangoproject.com/t/user-not-logging-in-with-custom-authentication-backend/28328/6 "2024-02-27T19:08:50Z")

</div>

can you show the exact code for CustomLoginForm? Also can you include complete code for this problem. I am also having the same issue but not able to troubleshoot. Thanks

---

<div class="post-metadata">

**Author:** ![andrew-kyle92](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/andrew-kyle92/32/19373_2.png) [@andrew-kyle92](https://forum.djangoproject.com/u/andrew-kyle92)\
**Post date:** [February 27, 2024, 7:26pm UTC](https://forum.djangoproject.com/t/user-not-logging-in-with-custom-authentication-backend/28328/7 "2024-02-27T19:26:03Z")

</div>

My CustomLoginForm is just a basic for that inherits AuthenticationForm

Here’s the code:

```auto
class CustomLoginForm(AuthenticationForm):
    username = forms.CharField(widget=forms.TextInput(attrs={"class": "form-control", "autofocus": True}))
    password = forms.CharField(widget=forms.PasswordInput(attrs={"class": "form-control"}))

```

Not all problems are the same though. If you want assistance with troubleshooting I would create a new post with the errors and code so that we can best assist you.
