Skip to content


Ticket #18616: contrib.auth signal user_login_fail #201

wants to merge 12 commits into from

4 participants


Note: it seems I made a typo on the branch name, it is ticket_18686 instead of ticket_18616.


I personally think user_login_failed would be a better name for this signal, to better match the verb form of the other two.

You raise a good point Brad, I'll update this pull request with another commit changing to this.

@micolous micolous per a suggestion by Brad Pitcher, I have changed the signal name to "…
…user_login_failed" to match the verb tense of the other signals emitted by contrib.auth.
Django member

@brad, @micolous Please incorporate the Doc PR into this PR.


I'll send a pull request your way, @micolous


GitHub won't let me send you a pull request, even when I branch directly from you. If you like you could pull my ticket_18616_docs branch to get the docs. I made updated to the sender documentation.




Sorry, looks like I forgot to get that sender doc change in that branch. I have made the change now if you want to pull again.

Django member

Remember folks to always mention in the ticket which pull request is the correct one!


Sorry, my mistake.


Merged Brad's documentation fixes.


This patch no longer applies cleanly to master. Can you fix it, or pull from We are in the middle of a sprint so we may manage to get it merged in today.

Django member

This was fixed in 7cc4068

@apollo13 apollo13 closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 12, 2012
  1. @micolous
  2. @micolous
  3. @brad
  4. @micolous

    per a suggestion by Brad Pitcher, I have changed the signal name to "…

    micolous committed
    …user_login_failed" to match the verb tense of the other signals emitted by contrib.auth.
Commits on Jul 17, 2012
  1. @brad
  2. @brad
Commits on Jul 18, 2012
  1. @brad

    fix copy/pasted sender doc

    brad committed
Commits on Jul 23, 2012
  1. @micolous
Commits on Sep 8, 2012
  1. @brad

    fix docs merge conflict

    brad committed
Commits on Sep 17, 2012
  1. @micolous

    Merge branch 'ticket_18616' of git:// into tick…

    micolous committed
    Resolved Conflicts:
  2. @micolous

    Merge branch 'django/master' into ticket_18686

    micolous committed
    Resolved Conflicts:
Commits on Sep 18, 2012
  1. @micolous
This page is out of date. Refresh to see the latest.
5 django/contrib/auth/
@@ -1,6 +1,6 @@
from django.core.exceptions import ImproperlyConfigured
from django.utils.importlib import import_module
-from django.contrib.auth.signals import user_logged_in, user_logged_out
+from django.contrib.auth.signals import user_logged_in, user_logged_out, user_login_failed
SESSION_KEY = '_auth_user_id'
BACKEND_SESSION_KEY = '_auth_user_backend'
@@ -45,6 +45,9 @@ def authenticate(**credentials):
# Annotate the user object with the path of the backend.
user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__)
return user
+ # The credentials supplied are invalid to all backends, fire signal
+ user_login_failed.send(sender=__name__, credentials=credentials)
def login(request, user):
1 django/contrib/auth/
@@ -1,4 +1,5 @@
from django.dispatch import Signal
user_logged_in = Signal(providing_args=['request', 'user'])
+user_login_failed = Signal(providing_args=['credentials'])
user_logged_out = Signal(providing_args=['request', 'user'])
14 django/contrib/auth/tests/
@@ -16,27 +16,39 @@ def listener_login(self, user, **kwargs):
def listener_logout(self, user, **kwargs):
+ def listener_login_failed(self, sender, credentials, **kwargs):
+ self.login_failed.append(credentials['username'])
def setUp(self):
"""Set up the listeners and reset the logged in/logged out counters"""
self.logged_in = []
self.logged_out = []
+ self.login_failed = []
+ signals.user_login_failed.connect(self.listener_login_failed)
def tearDown(self):
"""Disconnect the listeners"""
+ signals.user_login_failed.disconnect(self.listener_login_failed)
def test_login(self):
- # Only a successful login will trigger the signal.
+ # Only a successful login will trigger the success signal.
self.client.login(username='testclient', password='bad')
self.assertEqual(len(self.logged_in), 0)
+ self.assertEqual(len(self.login_failed), 1)
+ self.assertEqual(self.login_failed[0], 'testclient')
# Like this:
self.client.login(username='testclient', password='password')
self.assertEqual(len(self.logged_in), 1)
self.assertEqual(self.logged_in[0].username, 'testclient')
+ # Ensure there were no more failures.
+ self.assertEqual(len(self.login_failed), 1)
def test_logout_anonymous(self):
# The log_out function will still trigger the signal for anonymous
# users.
4 docs/releases/1.5.txt
@@ -121,6 +121,10 @@ Django 1.5 also includes several smaller improvements worth noting:
argument. By default the batch_size is unlimited except for SQLite where
single batch is limited so that 999 parameters per query isn't exceeded.
+* :mod:`django.contrib.auth` provides a new signal that is emitted
+ whenever a user fails to login successfully. See
+ :data:`~django.contrib.auth.signals.user_login_failed`
* The :setting:`LOGIN_URL` and :setting:`LOGIN_REDIRECT_URL` settings now also
accept view function names and
:ref:`named URL patterns <naming-url-patterns>`. This allows you to reduce
21 docs/topics/auth.txt
@@ -866,13 +866,15 @@ The auth framework uses two :doc:`signals </topics/signals>` that can be used
for notification when a user logs in or out.
.. data:: django.contrib.auth.signals.user_logged_in
+ :module:
+.. versionadded:: 1.3
Sent when a user logs in successfully.
Arguments sent with this signal:
- As above: the class of the user that just logged in.
+ The class of the user that just logged in.
The current :class:`~django.http.HttpRequest` instance.
@@ -881,6 +883,8 @@ Arguments sent with this signal:
The user instance that just logged in.
.. data:: django.contrib.auth.signals.user_logged_out
+ :module:
+.. versionadded:: 1.3
Sent when the logout method is called.
@@ -895,6 +899,21 @@ Sent when the logout method is called.
The user instance that just logged out or ``None`` if the
user was not authenticated.
+.. data:: django.contrib.auth.signals.user_login_failed
+ :module:
+.. versionadded:: 1.5
+Sent when the user failed to login successfully
+ The name of the module used for authentication.
+ A dictonary of keyword arguments containing the user credentials that
+ were passed to :func:`~django.contrib.auth.authenticate()` or
+ your own custom authentication backend. Most of the time this dictionary
+ will just include ``username`` and ``password``.
Limiting access to logged-in users
Something went wrong with that request. Please try again.