Skip to main content

Modern session-based opaque token authentication for Django REST Framework

Project description

RobustAuth

Modern session-based opaque token authentication for Django REST Framework.

RobustAuth replaces JWT complexity with secure, database-backed opaque tokens — giving you instant revocation, full session intelligence, and production-grade security controls out of the box.

PyPI version Django DRF Docs License: MIT


Why RobustAuth?

Feature DRF TokenAuth SimpleJWT RobustAuth
Instant token revocation ❌ (wait for expiry)
Refresh token rotation
Reuse detection
Multi-device session tracking
Single-session enforcement
Login / audit history
Device & browser detection ✅ (optional)
Hashed token storage N/A
Sliding sessions
Django admin integration

Installation

pip install robustauth

# Optional: device/browser detection
pip install robustauth[device]

Add to INSTALLED_APPS:

INSTALLED_APPS = [
    ...
    "robustauth",
]

Run migrations:

python manage.py migrate

Add URL patterns:

# urls.py
from django.urls import path, include

urlpatterns = [
    path("auth/", include("robustauth.urls")),
    ...
]

Quick Start

1. Configure (optional — sensible defaults apply)

# settings.py
ROBUST_AUTH = {
    "ACCESS_TOKEN_TTL": 900,          # 15 min
    "REFRESH_TOKEN_TTL": 604800,      # 7 days
    "SESSION_POLICY": "single",       # one device at a time
    "ROTATE_REFRESH_TOKENS": True,
    "REVOKE_ON_PASSWORD_CHANGE": True,
    "TRACK_IPS": True,
    "TRACK_USER_AGENTS": True,
    "MAX_SESSIONS": 3,                # used when SESSION_POLICY = "max_count"
}

2. Set authentication on your views

# settings.py
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "robustauth.authentication.RobustTokenAuthentication",
    ],
}

Or per-view:

from robustauth.authentication import RobustTokenAuthentication

class MyView(APIView):
    authentication_classes = [RobustTokenAuthentication]
    permission_classes = [IsAuthenticated]

API Endpoints

All endpoints are prefixed with wherever you mounted robustauth.urls.

POST /auth/login/

Authenticate a user and receive token pair.

Request:

{
  "username": "alice",
  "password": "secret"
}

Response 200:

{
  "access_token": "a3f9...",
  "refresh_token": "b7c2...",
  "session_id": "550e8400-e29b-...",
  "token_type": "Bearer"
}

POST /auth/token/refresh/

Exchange a refresh token for a new token pair. The old refresh token is invalidated.

Request:

{ "refresh_token": "b7c2..." }

Response 200:

{
  "access_token": "d1e4...",
  "refresh_token": "f5a8...",
  "token_type": "Bearer"
}

POST /auth/logout/

Revoke the current session. Requires Authorization: Bearer <access_token>.

Response 200:

{ "detail": "Logged out successfully." }

POST /auth/logout/all/

Revoke all sessions (optionally keep the current one alive).

Request:

{ "keep_current": true }

GET /auth/sessions/

List all active sessions for the authenticated user.

Response:

[
  {
    "id": "550e8400-...",
    "state": "active",
    "ip_address": "41.58.12.34",
    "device_type": "mobile",
    "os_family": "Android",
    "browser_family": "Chrome Mobile",
    "device_name": "Samsung SM-G991",
    "created_at": "2024-01-15T10:23:00Z",
    "last_activity": "2024-01-15T14:05:00Z",
    "is_current": true
  }
]

DELETE /auth/sessions/<uuid>/

Revoke a specific session by ID.


GET /auth/history/

Return the authentication event log for the authenticated user.

Query params: ?limit=50

Response:

[
  {
    "id": 1,
    "event": "login_success",
    "ip_address": "41.58.12.34",
    "user_agent": "Mozilla/5.0 ...",
    "extra": {},
    "timestamp": "2024-01-15T10:23:00Z"
  },
  ...
]

Session Policies

Control concurrent login behaviour via SESSION_POLICY:

Value Behaviour
"multi" Unlimited concurrent sessions (default)
"single" Only one active session per user — new login revokes all others
"max_count" At most MAX_SESSIONS active sessions; oldest revoked when limit hit
ROBUST_AUTH = {
    "SESSION_POLICY": "max_count",
    "MAX_SESSIONS": 3,
    "REVOKE_OLDEST_ON_LIMIT": True,   # False → raise error instead
}

Signals

Hook into authentication events in your own apps:

from robustauth import signals
from django.dispatch import receiver

@receiver(signals.token_reuse_detected)
def alert_security(sender, user, session, ip_address, **kwargs):
    # Send email, create alert, block IP, etc.
    SecurityAlert.objects.create(user=user, ip=ip_address)

@receiver(signals.brute_force_threshold_hit)
def handle_brute_force(sender, username, ip_address, failure_count, **kwargs):
    BlockedIP.objects.get_or_create(ip=ip_address)

@receiver(signals.user_logged_in)
def on_login(sender, user, session, **kwargs):
    send_new_login_email(user, session)

@receiver(signals.session_limit_reached)
def on_limit(sender, user, active_sessions, **kwargs):
    notify_user(user, "You've reached the maximum number of active sessions.")

Available signals:

Signal kwargs
user_logged_in user, session
user_logged_out user, session
token_reuse_detected user, session, ip_address
session_limit_reached user, active_sessions
brute_force_threshold_hit username, ip_address, failure_count

Password Change Integration

Automatically revoke all other sessions on password change:

from robustauth.session_manager import SessionManager

def change_password_view(request):
    # ... your password change logic ...
    user.set_password(new_password)
    user.save()

    # Revoke all sessions except the current one
    current_session = request.auth.session  # if using RobustTokenAuthentication
    SessionManager.on_password_change(user, current_session=current_session)

Middleware (optional)

Attach request.robust_session to all requests:

MIDDLEWARE = [
    ...
    "robustauth.middleware.RobustAuthMiddleware",
]

Then in any view:

def my_view(request):
    session = request.robust_session  # Session object or None

Cleanup

Remove expired tokens and prune history. Add to your cron or Celery beat:

python manage.py robustauth_cleanup

# Preview without deleting
python manage.py robustauth_cleanup --dry-run

Example Celery beat config:

CELERY_BEAT_SCHEDULE = {
    "robustauth-cleanup": {
        "task": "your_app.tasks.robustauth_cleanup",
        "schedule": crontab(hour=3, minute=0),  # daily at 3am
    }
}

Configuration Reference

Setting Default Description
ACCESS_TOKEN_TTL 900 Access token lifetime in seconds
REFRESH_TOKEN_TTL 604800 Refresh token lifetime in seconds
SESSION_POLICY "multi" "single" / "multi" / "max_count"
MAX_SESSIONS 5 Max concurrent sessions (max_count policy)
REVOKE_OLDEST_ON_LIMIT True Auto-revoke oldest when limit hit
ROTATE_REFRESH_TOKENS True Issue new refresh token on each use
REFRESH_TOKEN_REUSE_DETECTION True Revoke family + all sessions on reuse
REVOKE_ON_PASSWORD_CHANGE True Revoke all sessions on password change
HASH_TOKENS True Store sha256(token) instead of plaintext
TOKEN_BYTES 32 Random bytes for token generation
TRACK_IPS True Store client IP on sessions
TRACK_USER_AGENTS True Store User-Agent header
TRACK_DEVICE_INFO True Parse OS/browser from UA (ua-parser required)
STORE_LOGIN_HISTORY True Log successful logins
STORE_LOGOUT_HISTORY True Log logouts
STORE_FAILED_LOGINS True Log failed login attempts
MAX_HISTORY_ENTRIES 100 Max history rows kept per user
FAILED_LOGIN_THRESHOLD 5 Failures before brute_force_threshold_hit fires
FAILED_LOGIN_WINDOW 300 Window in seconds for counting failures
SLIDING_SESSION False Reset access token expiry on activity
SLIDING_SESSION_TTL 1800 Inactivity timeout for sliding sessions

Running Tests

pip install -e ".[dev]"
pytest

Changelog

0.1.0

  • Initial release
  • Opaque token authentication with hashed storage
  • Access + refresh token pair with rotation
  • Refresh token reuse detection with family revocation
  • Session policies: single / multi / max_count
  • Device and browser fingerprinting
  • Login / logout / failed login history
  • Brute-force threshold signal
  • Sliding sessions
  • Password change revocation
  • Django admin integration
  • robustauth_cleanup management command

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

robustauth-0.1.1.tar.gz (30.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

robustauth-0.1.1-py3-none-any.whl (31.0 kB view details)

Uploaded Python 3

File details

Details for the file robustauth-0.1.1.tar.gz.

File metadata

  • Download URL: robustauth-0.1.1.tar.gz
  • Upload date:
  • Size: 30.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for robustauth-0.1.1.tar.gz
Algorithm Hash digest
SHA256 4f19983c558ff8bd744b0a279866379f628b30159d4f7a999fa436816ca8d637
MD5 2de5b0401c94df2b076bb75f8db76ce5
BLAKE2b-256 6deaefd2913f5c286e65d7ec722f95f070a1a4bf46efd96690d47d2f7352c90e

See more details on using hashes here.

Provenance

The following attestation bundles were made for robustauth-0.1.1.tar.gz:

Publisher: publish.yml on VictorAO-django/robustauth

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file robustauth-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: robustauth-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 31.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for robustauth-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a4fbe679ba966ec4743824450bb58765d66de6b5d375b4fbfc3e4df7ce2a8023
MD5 ac43b06587c958fb60bdf13ad3828352
BLAKE2b-256 d782483950cfc5c6f2db0ec4dadbcf8929b362f115f33ee94f69ebae7e8fdbe8

See more details on using hashes here.

Provenance

The following attestation bundles were made for robustauth-0.1.1-py3-none-any.whl:

Publisher: publish.yml on VictorAO-django/robustauth

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page