Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication.
—
Multi-device session tracking, session metadata collection, and cross-device logout capabilities. Provides visibility and control over user sessions across different devices and browsers for enhanced security and user experience.
Core models for tracking and managing user sessions across devices.
class UserSession(models.Model):
"""
Track user sessions across devices and browsers.
"""
user: User = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
ip: str = models.GenericIPAddressField()
user_agent: str = models.TextField()
created_at: datetime = models.DateTimeField(auto_now_add=True)
last_seen_at: datetime = models.DateTimeField(auto_now=True)
session_key: str = models.CharField(max_length=40, unique=True)
def __str__(self) -> str: ...
def get_device_info(self) -> Dict[str, str]: ...
def get_location_info(self) -> Dict[str, str]: ...
def is_current_session(self, request: HttpRequest) -> bool: ...
def end_session(self) -> None: ...
class UserSessionActivity(models.Model):
"""
Track detailed activity within user sessions.
"""
session: UserSession = models.ForeignKey(UserSession, on_delete=models.CASCADE)
timestamp: datetime = models.DateTimeField(auto_now_add=True)
path: str = models.CharField(max_length=500)
method: str = models.CharField(max_length=10)
status_code: int = models.IntegerField()
def __str__(self) -> str: ...Django views for session management and monitoring.
class SessionsView(TemplateView):
"""
View for displaying user's active sessions.
"""
template_name: str = "usersessions/sessions.html"
def get_context_data(self, **kwargs) -> Dict[str, Any]: ...
class EndSessionView(View):
"""
End a specific user session.
"""
def post(self, request: HttpRequest, session_id: int) -> HttpResponse: ...
class EndAllSessionsView(View):
"""
End all user sessions except current one.
"""
def post(self, request: HttpRequest) -> HttpResponse: ...
class SessionDetailView(DetailView):
"""
Detailed view of a specific session.
"""
model: type = UserSession
template_name: str = "usersessions/session_detail.html"
context_object_name: str = "session"
def get_queryset(self) -> QuerySet: ...Middleware for automatic session tracking and management.
class UserSessionMiddleware:
"""
Middleware to track user sessions automatically.
"""
def __init__(self, get_response: Callable): ...
def __call__(self, request: HttpRequest) -> HttpResponse: ...
def process_request(self, request: HttpRequest) -> None:
"""
Process incoming request for session tracking.
Parameters:
- request: HTTP request object
"""
def process_response(self, request: HttpRequest, response: HttpResponse) -> HttpResponse:
"""
Process response for session activity logging.
Parameters:
- request: HTTP request object
- response: HTTP response object
Returns:
HTTP response object
"""Core functions for session creation, tracking, and management.
def create_user_session(request: HttpRequest, user: User) -> UserSession:
"""
Create a new user session record.
Parameters:
- request: HTTP request object
- user: User instance
Returns:
UserSession instance
"""
def get_user_session(request: HttpRequest) -> Optional[UserSession]:
"""
Get current user session from request.
Parameters:
- request: HTTP request object
Returns:
UserSession instance if found, None otherwise
"""
def update_session_activity(request: HttpRequest, response: HttpResponse = None) -> None:
"""
Update session activity with request details.
Parameters:
- request: HTTP request object
- response: Optional HTTP response object
"""
def end_user_session(session: UserSession) -> None:
"""
End a specific user session.
Parameters:
- session: UserSession instance to end
"""
def end_all_user_sessions(user: User, except_session: UserSession = None) -> int:
"""
End all sessions for a user.
Parameters:
- user: User instance
- except_session: Optional session to preserve
Returns:
Number of sessions ended
"""
def cleanup_expired_sessions(days: int = 30) -> int:
"""
Clean up expired/inactive sessions.
Parameters:
- days: Number of days to consider as expired
Returns:
Number of sessions cleaned up
"""Device and browser detection utilities.
def parse_user_agent(user_agent: str) -> Dict[str, str]:
"""
Parse user agent string for device information.
Parameters:
- user_agent: User agent string
Returns:
Dictionary with device information:
- browser: Browser name and version
- os: Operating system name and version
- device: Device type (desktop, mobile, tablet)
- is_mobile: Boolean indicating mobile device
- is_tablet: Boolean indicating tablet device
"""
def get_client_ip(request: HttpRequest) -> str:
"""
Get client IP address from request.
Parameters:
- request: HTTP request object
Returns:
Client IP address string
"""
def get_location_from_ip(ip: str) -> Dict[str, str]:
"""
Get approximate location from IP address.
Parameters:
- ip: IP address string
Returns:
Dictionary with location information:
- country: Country name
- region: Region/state name
- city: City name
- timezone: Timezone identifier
"""Security-related session management features.
def detect_suspicious_activity(user: User) -> List[Dict[str, Any]]:
"""
Detect suspicious session activity for user.
Parameters:
- user: User instance
Returns:
List of suspicious activity indicators
"""
def require_session_verification(user: User, threshold_hours: int = 24) -> bool:
"""
Check if user requires session verification based on activity.
Parameters:
- user: User instance
- threshold_hours: Hours since last activity to require verification
Returns:
True if verification required
"""
def send_new_session_notification(user: User, session: UserSession) -> None:
"""
Send notification for new session login.
Parameters:
- user: User instance
- session: New UserSession instance
"""
def log_security_event(user: User, event_type: str, details: Dict[str, Any]) -> None:
"""
Log security-related session events.
Parameters:
- user: User instance
- event_type: Type of security event
- details: Event details dictionary
"""Session analytics and reporting utilities.
def get_session_statistics(user: User, days: int = 30) -> Dict[str, Any]:
"""
Get session statistics for user.
Parameters:
- user: User instance
- days: Number of days to analyze
Returns:
Dictionary with session statistics:
- total_sessions: Total number of sessions
- active_sessions: Currently active sessions
- unique_devices: Number of unique devices
- unique_locations: Number of unique locations
- average_session_duration: Average session length
"""
def get_device_usage_report(user: User) -> List[Dict[str, Any]]:
"""
Get device usage report for user.
Parameters:
- user: User instance
Returns:
List of device usage statistics
"""
def generate_session_activity_report(user: User, start_date: datetime, end_date: datetime) -> Dict[str, Any]:
"""
Generate detailed session activity report.
Parameters:
- user: User instance
- start_date: Report start date
- end_date: Report end date
Returns:
Comprehensive activity report dictionary
"""from allauth.usersessions.models import UserSession
from allauth.usersessions.utils import create_user_session, get_user_session
# Create session on login
def login_user(request, user):
# Standard Django login
login(request, user)
# Create session tracking
user_session = create_user_session(request, user)
print(f"Session created: {user_session.session_key}")
# Get current session
current_session = get_user_session(request)
if current_session:
print(f"Current session from {current_session.ip}")
print(f"Device: {current_session.get_device_info()}")from allauth.usersessions.models import UserSession
from allauth.usersessions.utils import end_user_session, end_all_user_sessions
class UserSessionsView(LoginRequiredMixin, TemplateView):
template_name = 'account/sessions.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['sessions'] = UserSession.objects.filter(
user=self.request.user
).order_by('-last_seen_at')
return context
class EndSessionView(LoginRequiredMixin, View):
def post(self, request, session_id):
try:
session = UserSession.objects.get(
id=session_id,
user=request.user
)
end_user_session(session)
messages.success(request, "Session ended successfully")
except UserSession.DoesNotExist:
messages.error(request, "Session not found")
return redirect('account_sessions')
class EndAllSessionsView(LoginRequiredMixin, View):
def post(self, request):
current_session = get_user_session(request)
count = end_all_user_sessions(request.user, except_session=current_session)
messages.success(request, f"Ended {count} sessions")
return redirect('account_sessions')from allauth.usersessions.device import parse_user_agent, get_client_ip
# Parse user agent
user_agent = request.META.get('HTTP_USER_AGENT', '')
device_info = parse_user_agent(user_agent)
print(f"Browser: {device_info['browser']}")
print(f"OS: {device_info['os']}")
print(f"Device Type: {device_info['device']}")
print(f"Is Mobile: {device_info['is_mobile']}")
# Get client IP
client_ip = get_client_ip(request)
print(f"Client IP: {client_ip}")
# Get location (requires IP geolocation service)
location = get_location_from_ip(client_ip)
print(f"Location: {location['city']}, {location['country']}")from allauth.usersessions.security import (
detect_suspicious_activity,
send_new_session_notification,
log_security_event
)
# Check for suspicious activity
suspicious_activities = detect_suspicious_activity(user)
if suspicious_activities:
for activity in suspicious_activities:
print(f"Suspicious: {activity['type']} - {activity['description']}")
log_security_event(user, activity['type'], activity)
# Send notification for new session
def on_new_session(sender, user, session, **kwargs):
device_info = session.get_device_info()
if device_info['device'] != 'desktop':
send_new_session_notification(user, session)
# Connect to login signal
from django.contrib.auth.signals import user_logged_in
user_logged_in.connect(on_new_session)from allauth.usersessions.analytics import (
get_session_statistics,
get_device_usage_report,
generate_session_activity_report
)
# Get session statistics
stats = get_session_statistics(user, days=30)
print(f"Total sessions: {stats['total_sessions']}")
print(f"Active sessions: {stats['active_sessions']}")
print(f"Unique devices: {stats['unique_devices']}")
print(f"Average duration: {stats['average_session_duration']}")
# Device usage report
device_report = get_device_usage_report(user)
for device in device_report:
print(f"{device['name']}: {device['session_count']} sessions")
# Detailed activity report
from datetime import datetime, timedelta
end_date = datetime.now()
start_date = end_date - timedelta(days=7)
activity_report = generate_session_activity_report(user, start_date, end_date)
print(f"Page views: {activity_report['page_views']}")
print(f"Most active hours: {activity_report['peak_hours']}")<!-- User sessions page -->
<div class="user-sessions">
<h2>Active Sessions</h2>
{% for session in sessions %}
<div class="session-card">
<div class="session-info">
<strong>{{ session.get_device_info.browser }}</strong>
<small>{{ session.get_device_info.os }}</small>
</div>
<div class="session-details">
<p>IP: {{ session.ip }}</p>
<p>Location: {{ session.get_location_info.city }}, {{ session.get_location_info.country }}</p>
<p>Last active: {{ session.last_seen_at|timesince }} ago</p>
{% if session.is_current_session:request %}
<span class="badge badge-success">Current Session</span>
{% else %}
<form method="post" action="{% url 'end_session' session.id %}">
{% csrf_token %}
<button type="submit" class="btn btn-sm btn-danger">End Session</button>
</form>
{% endif %}
</div>
</div>
{% endfor %}
<form method="post" action="{% url 'end_all_sessions' %}">
{% csrf_token %}
<button type="submit" class="btn btn-warning">End All Other Sessions</button>
</form>
</div># In Django settings.py
# Enable user sessions
INSTALLED_APPS = [
# ...
'allauth.usersessions',
]
# Add middleware
MIDDLEWARE = [
# ... other middleware
'allauth.usersessions.middleware.UserSessionMiddleware',
]
# User sessions settings
USERSESSIONS_TRACK_ACTIVITY = True
USERSESSIONS_IP_GEOLOCATION = True
USERSESSIONS_CLEANUP_DAYS = 30
USERSESSIONS_NOTIFY_NEW_SESSIONS = True
# Security settings
USERSESSIONS_DETECT_SUSPICIOUS = True
USERSESSIONS_MAX_SESSIONS_PER_USER = 10
USERSESSIONS_SESSION_TIMEOUT_HOURS = 24
# URL configuration
urlpatterns = [
# ...
path('sessions/', include('allauth.usersessions.urls')),
]# Clean up old sessions
python manage.py cleanup_sessions --days 30
# Generate session report
python manage.py session_report --user-id 123 --format csv
# Monitor suspicious activity
python manage.py monitor_sessions --suspicious-onlyInstall with Tessl CLI
npx tessl i tessl/pypi-django-allauth