A plug-and-play Django app that adds trusted device management to your API authentication system using
djangorestframework-simplejwt. Automatically associates tokens with user devices, tracks login locations,
and enables per-device control over access and session management.
- π JWT tokens include a unique
device_uid - π Auto-detect IP, region, and city via ipapi.co
- π‘οΈ Per-device session tracking with update/delete restrictions
- π Custom
TokenObtainPair,TokenRefresh, andTokenVerifyviews - πͺ Logout unwanted sessions from the device list
- π§Ό Automatic cleanup, optional global control rules
- π§© API-ready β supports DRF out of the box
- βοΈ Fully customizable via
TRUSTED_DEVICEDjango settings - π« Rejects refresh/verify from unknown or expired devices
pip install django-trusted-deviceAdd to your INSTALLED_APPS:
INSTALLED_APPS = [
...
'trusted_devices',
'rest_framework_simplejwt.token_blacklist',
]Run migrations:
python manage.py migrateCustomize behavior in settings.py:
TRUSTED_DEVICE = {
"DELETE_DELAY_MINUTES": 60 * 24 * 7, # 7 days
"UPDATE_DELAY_MINUTES": 60, # 1 hour
"ALLOW_GLOBAL_DELETE": True,
"ALLOW_GLOBAL_UPDATE": True,
}Replace default SimpleJWT serializers with TrustedDevice serializers.:
from datetime import timedelta
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'trusted_devices.authentication.TrustedDeviceAuthentication',
),
}
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=60),
"REFRESH_TOKEN_LIFETIME": timedelta(days=30),
"AUTH_HEADER_TYPES": ("Bearer",),
"TOKEN_OBTAIN_SERIALIZER": 'trusted_devices.serializers.TrustedDeviceTokenObtainPairSerializer',
"TOKEN_REFRESH_SERIALIZER": 'trusted_devices.serializers.TrustedDeviceTokenRefreshSerializer',
"TOKEN_VERIFY_SERIALIZER": 'trusted_devices.serializers.TrustedDeviceTokenVerifySerializer',
}Replace the default SimpleJWT views with:
from trusted_devices.views import (
TrustedDeviceTokenObtainPairView,
TrustedDeviceTokenRefreshView,
TrustedDeviceTokenVerifyView,
)
urlpatterns = [
path('api/token/', TrustedDeviceTokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TrustedDeviceTokenRefreshView.as_view(), name='token_refresh'),
path('api/token/verify/', TrustedDeviceTokenVerifyView.as_view(), name='token_verify'),
]Use the provided TrustedDeviceViewSet:
from trusted_devices.views import TrustedDeviceViewSet
router.register(r'trusted-devices', TrustedDeviceViewSet, basename='trusted-device')Endpoints:
GET /trusted-devicesβ List all trusted devicesDELETE /trusted-devices/{device_uid}β Delete a devicePATCH /trusted-devices/{device_uid}β Update device permissions
Each trusted device includes:
device_uid: Unique UUIDuser_agent: Browser or device stringip_address: IP addresscountry,region,city: Geolocation (viaipapi.co)last_seen,created_at: Timestampscan_delete_other_devices,can_update_other_devices: Optional privileges
- During login, a
device_uidis generated and embedded in the token. - Clients use that token (with
device_uid) for refresh/verify. - Each request is linked to a known device.
- Users can manage or restrict their devices via API or Admin.
# π§© Create and activate a uv-managed virtual environment
uv venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# π¦ Install the package in editable mode with dev extras
uv pip install -e ".[dev]"
# π§ͺ Run the test suite
pytest- Django
- Django REST Framework
- djangorestframework-simplejwt
- ipapi.co (for IP geolocation)
| Field | Purpose |
|---|---|
device_uid |
UUID primary key |
user_agent, ip_address |
Device fingerprint |
country / region / city |
Geoβlookup |
last_seen / created_at |
Activity timestamps |
can_update_other_devices |
Granular permission |
can_delete_other_devices |
Granular permission |
We love community contributions! To collaborate:
-
Fork the repo and create a feature branch:
git checkout -b feature/my-amazing-idea
-
Follow code style β run:
make lint # runs flake8, isort, black -
Write & run tests:
pytest
-
Commit with clear messages and open a Pull Request. GitHub Actions will lint + test your branch automatically.
- π‘ Questions / ideas β GitHub Discussions
- π Bugs / feature requests β GitHub Issues
- PRs require at least one approval and passing CI
- We squashβmerge to keep history clean
- Follows Semantic Versioning (
MAJOR.MINOR.PATCH), tagged asvX.Y.Z
Made with β€οΈ by Jahongir Ganiev Security questions or commercial support? Open an issue or email [email protected]