API Reference
This page documents Nova2FA's Python API for programmatic usage.
Models
UserTwoFactorSettings
Stores user 2FA configuration and state.
from nova2fa.models import UserTwoFactorSettings
# Get user's settings
settings = UserTwoFactorSettings.objects.get(user=user)
Fields
| Field | Type | Description |
|---|---|---|
user |
ForeignKey | Reference to Django user |
is_enabled |
BooleanField | Whether 2FA is enabled |
method |
CharField | Active method ('email' or 'totp') |
totp_secret |
CharField | TOTP secret key (encrypted in v1.1.0+) |
backup_codes |
JSONField | List of backup codes (hashed in v1.1.0+) |
used_backup_codes |
JSONField | List of used backup codes |
failed_attempts |
IntegerField | Failed verification attempts (v1.1.0+) |
locked_until |
DateTimeField | Account lockout expiration (v1.1.0+) |
last_verified |
DateTimeField | Last verification timestamp |
created_at |
DateTimeField | When settings were created |
updated_at |
DateTimeField | Last update timestamp |
Methods
needs_verification()
Check if user needs to verify 2FA.
if settings.needs_verification():
# Redirect to verification
redirect('nova2fa:verify')
Returns: bool
update_last_verified()
Update the last verified timestamp to now.
settings.update_last_verified()
Returns: None
verify_backup_code(code)
Verify a backup code and mark it as used.
if settings.verify_backup_code('ABCD1234'):
print("Valid backup code!")
Parameters:
code(str): The backup code to verify
Returns: bool - True if valid, False otherwise
get_available_backup_codes()
Get list of unused backup codes.
codes = settings.get_available_backup_codes()
print(f"You have {len(codes)} codes remaining")
Returns: list of strings
has_available_backup_codes()
Check if user has any unused backup codes.
if not settings.has_available_backup_codes():
# Warn user to generate new codes
pass
Returns: bool
EmailOTP
Stores email one-time passwords.
from nova2fa.models import EmailOTP
# Get latest OTP for user
otp = EmailOTP.objects.filter(user=user).latest('created_at')
Fields
| Field | Type | Description |
|---|---|---|
user |
ForeignKey | Reference to Django user |
code |
CharField | The 6-digit OTP code |
created_at |
DateTimeField | When OTP was created |
expires_at |
DateTimeField | When OTP expires |
is_used |
BooleanField | Whether OTP has been used |
Methods
is_valid()
Check if OTP is still valid (not used and not expired).
if otp.is_valid():
# OTP can be used
pass
Returns: bool
mark_as_used()
Mark the OTP as used.
otp.mark_as_used()
Returns: None
Registry
register_method()
Register a custom 2FA method.
from nova2fa.registry import register_method
from myapp.methods import SMSMethod
register_method('sms', SMSMethod())
Parameters:
code(str): Unique identifier for the methodhandler(Base2FAMethod): Instance of method handler
Returns: None
get_method()
Get a registered 2FA method.
from nova2fa.registry import get_method
method = get_method('email')
if method:
method.send(user)
Parameters:
code(str): Method identifier
Returns: Base2FAMethod instance or None
get_enabled_methods()
Get all enabled methods based on settings.
from nova2fa.registry import get_enabled_methods
methods = get_enabled_methods()
for code, handler in methods.items():
print(f"{code}: {handler.verbose_name}")
Returns: dict of {code: handler}
Methods
Base2FAMethod
Base class for all 2FA methods.
from nova2fa.methods.base import Base2FAMethod
class CustomMethod(Base2FAMethod):
name = "custom"
verbose_name = "Custom Method"
def send(self, user):
# Implementation
return True
def verify(self, user, token):
# Implementation
return True
Required Attributes
name(str): Unique method identifierverbose_name(str): Human-readable name
Required Methods
send(user)
Send the 2FA token to the user.
Parameters:
user: Django user instance
Returns: bool - True if sent successfully
verify(user, token)
Verify the provided token.
Parameters:
user: Django user instancetoken(str): Token to verify
Returns: bool - True if valid
Optional Methods
setup(user)
Perform setup for this method (e.g., generate secret).
Parameters:
user: Django user instance
Returns: dict - Setup data
is_configured(user)
Check if method is configured for user.
Parameters:
user: Django user instance
Returns: bool
EmailOTPMethod
Email-based OTP method.
from nova2fa.methods import EmailOTPMethod
method = EmailOTPMethod()
method.send(user) # Sends OTP via email
method.verify(user, '123456') # Verifies code
TOTPMethod
Time-based OTP method (authenticator apps).
from nova2fa.methods import TOTPMethod
method = TOTPMethod()
setup_data = method.setup(user) # Returns QR code path, secret
method.verify(user, '123456') # Verifies TOTP code
BackupCodesMethod
Backup codes method.
from nova2fa.methods import BackupCodesMethod
method = BackupCodesMethod()
setup_data = method.setup(user) # Generates new codes
method.verify(user, 'ABCD1234') # Verifies backup code
Utilities
Checking 2FA Status
from nova2fa.models import UserTwoFactorSettings
def user_has_2fa(user):
"""Check if user has 2FA enabled."""
try:
settings = UserTwoFactorSettings.objects.get(user=user)
return settings.is_enabled
except UserTwoFactorSettings.DoesNotExist:
return False
Programmatically Enabling 2FA
from nova2fa.models import UserTwoFactorSettings
from nova2fa.methods import EmailOTPMethod, BackupCodesMethod
def enable_email_2fa(user):
"""Enable email 2FA for a user."""
settings, created = UserTwoFactorSettings.objects.get_or_create(user=user)
# Generate backup codes
backup_method = BackupCodesMethod()
backup_data = backup_method.setup(user)
# Enable 2FA
settings.is_enabled = True
settings.method = 'email'
settings.backup_codes = backup_data['codes']
settings.save()
return settings
Getting 2FA Statistics
from nova2fa.models import UserTwoFactorSettings
from django.db.models import Count
def get_2fa_stats():
"""Get 2FA adoption statistics."""
total_users = UserTwoFactorSettings.objects.count()
enabled = UserTwoFactorSettings.objects.filter(is_enabled=True).count()
methods = UserTwoFactorSettings.objects.filter(
is_enabled=True
).values('method').annotate(count=Count('method'))
return {
'total_users': total_users,
'enabled': enabled,
'adoption_rate': (enabled / total_users * 100) if total_users > 0 else 0,
'methods': dict((m['method'], m['count']) for m in methods)
}
Session Management
from django.utils import timezone
def mark_2fa_verified(request):
"""Mark session as 2FA verified."""
request.session['nova2fa_verified_at'] = timezone.now().isoformat()
request.session.save()
def clear_2fa_verification(request):
"""Clear 2FA verification from session."""
if 'nova2fa_verified_at' in request.session:
del request.session['nova2fa_verified_at']
request.session.save()
Middleware
Nova2FAMiddleware
The middleware automatically enforces 2FA verification.
Configuration:
# settings.py
MIDDLEWARE = [
# ...
'nova2fa.middleware.Nova2FAMiddleware',
]
Behavior:
- Checks if user is authenticated
- Checks if path is exempt
- Checks if user has 2FA enabled
- Checks if session is verified
- Redirects to verification if needed
Signals
Nova2FA creates UserTwoFactorSettings automatically when users are created:
# In your app
from django.contrib.auth import get_user_model
User = get_user_model()
user = User.objects.create_user('john', 'john@example.com', 'password')
# Nova2FA automatically creates settings
assert hasattr(user, 'nova2fa_settings')
Example: Custom Dashboard
# views.py
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from nova2fa.models import UserTwoFactorSettings, EmailOTP
from django.utils import timezone
from datetime import timedelta
@login_required
def security_dashboard(request):
"""Custom security dashboard with 2FA info."""
try:
settings = UserTwoFactorSettings.objects.get(user=request.user)
has_2fa = settings.is_enabled
method = settings.get_method_display() if has_2fa else None
# Get recent OTP attempts
recent_otps = EmailOTP.objects.filter(
user=request.user,
created_at__gte=timezone.now() - timedelta(days=7)
).count()
# Check backup codes
backup_codes_remaining = len(settings.get_available_backup_codes())
except UserTwoFactorSettings.DoesNotExist:
has_2fa = False
method = None
recent_otps = 0
backup_codes_remaining = 0
context = {
'has_2fa': has_2fa,
'method': method,
'recent_otps': recent_otps,
'backup_codes_remaining': backup_codes_remaining,
}
return render(request, 'dashboard.html', context)
Next Steps
- Review Customization Guide for template customization
- Check GitHub Repository for examples