Overview
The allauth.usersessions app allows users to view and manage all their active sessions across different devices and browsers. This is essential for security-conscious applications where users need visibility and control over their account access.
Installation
Add the usersessions app to your Django project:
INSTALLED_APPS = [
# ...
'django.contrib.humanize', # Required for user-friendly date formatting
'allauth.usersessions',
# ...
]
Run migrations to create the necessary database tables:
Basic Configuration
By default, user sessions are created at login but not actively tracked. To enable session tracking:
# Track session activity (IP address, user agent, last seen timestamp)
USERSESSIONS_TRACK_ACTIVITY = True
# Add the middleware to enable tracking
MIDDLEWARE = [
# ...
'allauth.usersessions.middleware.UserSessionsMiddleware',
# ...
]
The middleware is only required when USERSESSIONS_TRACK_ACTIVITY = True. Without it, sessions are created at login but not updated during subsequent requests.
URL Configuration
Include the usersessions URLs in your project:
from django.urls import path, include
urlpatterns = [
# ...
path('accounts/', include('allauth.urls')), # This includes usersessions URLs
# ...
]
The main URL endpoint is:
/accounts/sessions/ - List and manage active sessions
User Session Model
Each session is stored in the UserSession model with the following fields:
| Field | Description |
|---|
user | Foreign key to the user |
session_key | Django session key (unique) |
ip | IP address of the session |
user_agent | Browser/device user agent string |
created_at | When the session was created |
last_seen_at | Last activity timestamp (if tracking enabled) |
data | JSON field for additional metadata |
Displaying Active Sessions
Create a view to show users their active sessions:
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from allauth.usersessions.models import UserSession
@login_required
def my_sessions(request):
# Get all active sessions for the current user
sessions = UserSession.objects.purge_and_list(request.user)
return render(request, 'my_sessions.html', {
'sessions': sessions,
'current_session_key': request.session.session_key,
})
{% load humanize %}
<h2>Active Sessions</h2>
<p>These are all devices currently logged into your account.</p>
<ul>
{% for session in sessions %}
<li>
<strong>{{ session.user_agent|truncatewords:8 }}</strong>
<br>
IP: {{ session.ip }}
<br>
Created: {{ session.created_at|naturaltime }}
{% if session.is_current %}
<span class="badge">Current Session</span>
{% endif %}
</li>
{% endfor %}
</ul>
Ending Sessions
Allow users to terminate specific sessions:
from django.contrib import messages
from django.shortcuts import redirect
from allauth.usersessions.models import UserSession
@login_required
def end_session(request, session_id):
try:
session = UserSession.objects.get(
id=session_id,
user=request.user
)
# Don't allow ending the current session this way
if session.is_current():
messages.error(request, "Cannot end your current session. Use logout instead.")
else:
session.end()
messages.success(request, "Session ended successfully.")
except UserSession.DoesNotExist:
messages.error(request, "Session not found.")
return redirect('my_sessions')
Ending All Other Sessions
Implement a “logout all other devices” feature:
from allauth.usersessions.adapter import get_adapter
@login_required
def logout_all_other_sessions(request):
# Get all sessions except the current one
sessions = UserSession.objects.filter(
user=request.user
).exclude(
session_key=request.session.session_key
)
# End all sessions using the adapter
adapter = get_adapter()
adapter.end_sessions(sessions)
messages.success(
request,
f"Logged out {sessions.count()} other session(s)."
)
return redirect('my_sessions')
Security Notifications
Detect and notify users when their session’s IP or user agent changes:
from django.dispatch import receiver
from django.core.mail import send_mail
from allauth.usersessions.signals import session_client_changed
@receiver(session_client_changed)
def notify_session_change(sender, request, from_session, to_session, **kwargs):
"""Notify user when their session IP or user agent changes."""
user = request.user
# Send security notification
send_mail(
subject='Security Alert: Session Details Changed',
message=f"""
Your session details have changed:
Previous IP: {from_session.ip}
New IP: {to_session.ip}
Previous Device: {from_session.user_agent}
New Device: {to_session.user_agent}
If this wasn't you, please secure your account immediately.
""",
from_email='[email protected]',
recipient_list=[user.email],
)
Register the signal handler:
from django.apps import AppConfig
class MyAppConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'myapp'
def ready(self):
import myapp.signals # noqa
Custom Adapter
Customize session management behavior:
from allauth.usersessions.adapter import DefaultUserSessionsAdapter
class MyUserSessionsAdapter(DefaultUserSessionsAdapter):
def end_sessions(self, sessions):
"""Override to add custom logic when sessions are ended."""
# Log session termination
for session in sessions:
print(f"Ending session {session.id} for user {session.user}")
session.end()
USERSESSIONS_ADAPTER = 'myapp.adapters.MyUserSessionsAdapter'
Session Cleanup
The purge_and_list() method automatically removes stale sessions (where the Django session no longer exists):
# Manually purge stale sessions for a user
sessions = UserSession.objects.purge_and_list(user)
Consider adding a periodic cleanup task:
management/commands/cleanup_sessions.py
from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model
from allauth.usersessions.models import UserSession
class Command(BaseCommand):
help = 'Remove stale user sessions'
def handle(self, *args, **options):
User = get_user_model()
total_purged = 0
for user in User.objects.all():
sessions = UserSession.objects.purge_and_list(user)
purged = UserSession.objects.filter(user=user).count() - len(sessions)
total_purged += purged
self.stdout.write(
self.style.SUCCESS(f'Purged {total_purged} stale sessions')
)
Configuration Reference
USERSESSIONS_ADAPTER
Default: "allauth.usersessions.adapter.DefaultUserSessionsAdapter"
Path to the adapter class for customizing session management behavior.
USERSESSIONS_TRACK_ACTIVITY
Default: False
When enabled, sessions are actively tracked:
- IP address is updated on each request
- User agent is updated on each request
last_seen_at timestamp is updated
Requires allauth.usersessions.middleware.UserSessionsMiddleware in MIDDLEWARE.
Best Practices
-
Enable Activity Tracking: Set
USERSESSIONS_TRACK_ACTIVITY = True to maintain accurate session information.
-
Monitor Session Changes: Use the
session_client_changed signal to detect suspicious activity.
-
Regular Cleanup: Implement periodic cleanup of stale sessions to keep your database clean.
-
User Education: Provide clear information about active sessions in your UI so users understand what they’re seeing.
-
Security Alerts: Consider sending notifications for critical events like:
- New login from unknown device
- IP address changes
- All sessions terminated
-
Session Limits: Consider implementing limits on concurrent sessions per user if needed for your security model.
Complete Example
Here’s a complete implementation:
INSTALLED_APPS = [
'django.contrib.humanize',
'allauth',
'allauth.account',
'allauth.usersessions',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'allauth.usersessions.middleware.UserSessionsMiddleware',
]
USERSESSIONS_TRACK_ACTIVITY = True
USERSESSIONS_ADAPTER = 'myapp.adapters.MyUserSessionsAdapter'
# Enable security notifications
ACCOUNT_EMAIL_NOTIFICATIONS = True
This provides users with complete visibility and control over their account sessions across all devices.