0
# Serializers
1
2
Validation and processing classes for JWT authentication workflows, handling user credentials, token verification, and refresh operations. These serializers integrate with Django REST Framework's validation system to process JWT authentication requests.
3
4
## Capabilities
5
6
### JWT Authentication Serializer
7
8
Validates username/password credentials and generates JWT tokens for successful authentication.
9
10
```python { .api }
11
class JSONWebTokenSerializer(Serializer):
12
# Dynamic fields based on user model
13
# username_field: CharField (dynamically added based on User.USERNAME_FIELD)
14
# password: PasswordField (write-only)
15
16
def __init__(self, *args, **kwargs):
17
"""
18
Dynamically adds username field based on User model configuration.
19
20
Adds:
21
- Username field (name from User.USERNAME_FIELD)
22
- Password field (write-only with password input type)
23
"""
24
25
@property
26
def username_field(self):
27
"""
28
Returns the username field name from the User model.
29
30
Returns:
31
str: Field name used for username (e.g., 'username', 'email')
32
"""
33
34
def validate(self, attrs):
35
"""
36
Validates credentials and returns token with user data.
37
38
Args:
39
attrs (dict): Input data containing username and password
40
41
Returns:
42
dict: Contains 'token' (JWT string) and 'user' (User instance)
43
44
Raises:
45
ValidationError: For invalid credentials, inactive users, or missing fields
46
47
Validation Process:
48
1. Extracts username and password from input
49
2. Authenticates user via Django's authenticate()
50
3. Checks if user account is active
51
4. Generates JWT payload and token
52
5. Returns token and user data
53
"""
54
```
55
56
### Base Verification Serializer
57
58
Abstract base class providing common token validation functionality for verification and refresh operations.
59
60
```python { .api }
61
class VerificationBaseSerializer(Serializer):
62
token = CharField()
63
64
def validate(self, attrs):
65
"""
66
Abstract validation method to be implemented by subclasses.
67
68
Args:
69
attrs (dict): Input data containing token
70
71
Raises:
72
NotImplementedError: Must be overridden by subclasses
73
"""
74
75
def _check_payload(self, token):
76
"""
77
Validates JWT token and returns decoded payload.
78
79
Args:
80
token (str): JWT token string
81
82
Returns:
83
dict: Decoded JWT payload
84
85
Raises:
86
ValidationError: For expired, malformed, or invalid tokens
87
88
Validation includes:
89
- Token signature verification
90
- Expiration time checking
91
- Payload structure validation
92
"""
93
94
def _check_user(self, payload):
95
"""
96
Validates user from JWT payload and returns User instance.
97
98
Args:
99
payload (dict): Decoded JWT payload
100
101
Returns:
102
User: Active user instance
103
104
Raises:
105
ValidationError: For missing users, inactive accounts, or invalid payloads
106
107
Validation includes:
108
- Username extraction from payload
109
- User existence verification
110
- User account status checking
111
"""
112
```
113
114
### Token Verification Serializer
115
116
Validates JWT tokens and confirms their authenticity without generating new tokens.
117
118
```python { .api }
119
class VerifyJSONWebTokenSerializer(VerificationBaseSerializer):
120
def validate(self, attrs):
121
"""
122
Verifies token validity and returns token with user data.
123
124
Args:
125
attrs (dict): Input data containing token to verify
126
127
Returns:
128
dict: Contains 'token' (original JWT) and 'user' (User instance)
129
130
Raises:
131
ValidationError: For invalid, expired, or malformed tokens
132
133
Process:
134
1. Validates token signature and expiration
135
2. Extracts and validates user from payload
136
3. Returns original token and user data
137
"""
138
```
139
140
### Token Refresh Serializer
141
142
Validates existing tokens and generates new tokens with extended expiration times.
143
144
```python { .api }
145
class RefreshJSONWebTokenSerializer(VerificationBaseSerializer):
146
def validate(self, attrs):
147
"""
148
Validates token and generates refreshed token with new expiration.
149
150
Args:
151
attrs (dict): Input data containing token to refresh
152
153
Returns:
154
dict: Contains 'token' (new JWT) and 'user' (User instance)
155
156
Raises:
157
ValidationError: For invalid tokens, expired refresh windows, or missing orig_iat
158
159
Process:
160
1. Validates existing token signature and structure
161
2. Extracts and validates user from payload
162
3. Checks original issued-at time (orig_iat) for refresh eligibility
163
4. Verifies refresh hasn't exceeded maximum allowed time
164
5. Generates new token with extended expiration
165
6. Preserves original issued-at time in new token
166
167
Requirements:
168
- Token must contain 'orig_iat' field
169
- Current time must be within refresh expiration window
170
- JWT_ALLOW_REFRESH must be enabled in settings
171
"""
172
```
173
174
## Usage Examples
175
176
### Custom Authentication Serializer
177
178
```python
179
from rest_framework_jwt.serializers import JSONWebTokenSerializer
180
from rest_framework import serializers
181
from django.contrib.auth import authenticate
182
183
class CustomJWTSerializer(JSONWebTokenSerializer):
184
# Add extra fields
185
remember_me = serializers.BooleanField(default=False)
186
187
def validate(self, attrs):
188
# Get standard validation result
189
validated_data = super().validate(attrs)
190
191
# Customize token expiration based on remember_me
192
if attrs.get('remember_me'):
193
user = validated_data['user']
194
195
# Generate custom payload with longer expiration
196
from rest_framework_jwt.utils import jwt_payload_handler, jwt_encode_handler
197
from datetime import timedelta
198
199
payload = jwt_payload_handler(user)
200
payload['exp'] = payload['exp'] + timedelta(days=30) # Extend expiration
201
202
validated_data['token'] = jwt_encode_handler(payload)
203
204
return validated_data
205
```
206
207
### Custom Token Validation
208
209
```python
210
from rest_framework_jwt.serializers import VerifyJSONWebTokenSerializer
211
from rest_framework import serializers
212
213
class CustomVerifySerializer(VerifyJSONWebTokenSerializer):
214
def validate(self, attrs):
215
# Standard validation
216
validated_data = super().validate(attrs)
217
218
# Add custom business logic
219
user = validated_data['user']
220
221
# Check additional user requirements
222
if not user.profile.api_access_enabled:
223
raise serializers.ValidationError("API access is disabled for this user")
224
225
# Log token verification
226
self.log_token_verification(user, attrs['token'])
227
228
return validated_data
229
230
def log_token_verification(self, user, token):
231
# Custom logging logic
232
import logging
233
logger = logging.getLogger('jwt_auth')
234
logger.info(f"Token verified for user {user.username}")
235
```
236
237
### Manual Serializer Usage
238
239
```python
240
from rest_framework_jwt.serializers import JSONWebTokenSerializer, RefreshJSONWebTokenSerializer
241
242
# Manual authentication
243
auth_serializer = JSONWebTokenSerializer(data={
244
'username': 'testuser',
245
'password': 'testpass123'
246
})
247
248
if auth_serializer.is_valid():
249
token = auth_serializer.validated_data['token']
250
user = auth_serializer.validated_data['user']
251
print(f"Authentication successful for {user.username}")
252
else:
253
print(f"Authentication failed: {auth_serializer.errors}")
254
255
# Manual token refresh
256
refresh_serializer = RefreshJSONWebTokenSerializer(data={
257
'token': token
258
})
259
260
if refresh_serializer.is_valid():
261
new_token = refresh_serializer.validated_data['token']
262
print(f"Token refreshed successfully")
263
else:
264
print(f"Token refresh failed: {refresh_serializer.errors}")
265
```
266
267
### Integration with DRF Views
268
269
```python
270
from rest_framework.views import APIView
271
from rest_framework.response import Response
272
from rest_framework_jwt.serializers import JSONWebTokenSerializer
273
274
class CustomAuthView(APIView):
275
def post(self, request):
276
serializer = JSONWebTokenSerializer(data=request.data)
277
278
if serializer.is_valid():
279
# Custom response formatting
280
response_data = {
281
'success': True,
282
'token': serializer.validated_data['token'],
283
'user': {
284
'id': serializer.validated_data['user'].id,
285
'username': serializer.validated_data['user'].username,
286
},
287
'message': 'Authentication successful'
288
}
289
return Response(response_data)
290
else:
291
return Response({
292
'success': False,
293
'errors': serializer.errors
294
}, status=400)
295
```
296
297
## Field Validation
298
299
### Dynamic Username Field
300
301
The `JSONWebTokenSerializer` dynamically adds the username field based on your User model configuration:
302
303
```python
304
# If User.USERNAME_FIELD = 'email'
305
# Serializer will have 'email' field instead of 'username'
306
307
# If User.USERNAME_FIELD = 'username'
308
# Serializer will have 'username' field (default)
309
310
# Custom user model example
311
class CustomUser(AbstractUser):
312
email = models.EmailField(unique=True)
313
USERNAME_FIELD = 'email' # Use email for authentication
314
315
# JSONWebTokenSerializer will automatically use 'email' field
316
```
317
318
### Password Field
319
320
The password field is automatically configured with:
321
- Write-only access (not included in serialized output)
322
- Password input type for forms
323
- Required validation
324
325
## Error Handling
326
327
Serializers raise `ValidationError` for various conditions:
328
329
```python
330
from rest_framework import serializers
331
332
# Authentication errors
333
{
334
"non_field_errors": ["Unable to log in with provided credentials."]
335
}
336
337
# Field validation errors
338
{
339
"username": ["This field is required."],
340
"password": ["This field is required."]
341
}
342
343
# User account errors
344
{
345
"non_field_errors": ["User account is disabled."]
346
}
347
348
# Token validation errors
349
{
350
"token": ["This field is required."]
351
}
352
353
# JWT-specific errors
354
{
355
"non_field_errors": ["Signature has expired."]
356
}
357
{
358
"non_field_errors": ["Error decoding signature."]
359
}
360
361
# Refresh-specific errors
362
{
363
"non_field_errors": ["Refresh has expired."]
364
}
365
{
366
"non_field_errors": ["orig_iat field is required."]
367
}
368
```
369
370
## Configuration Dependencies
371
372
Serializers depend on various JWT settings:
373
374
- `JWT_PAYLOAD_HANDLER`: Function to generate JWT payloads
375
- `JWT_ENCODE_HANDLER`: Function to encode JWT tokens
376
- `JWT_DECODE_HANDLER`: Function to decode JWT tokens
377
- `JWT_PAYLOAD_GET_USERNAME_HANDLER`: Function to extract username from payload
378
- `JWT_ALLOW_REFRESH`: Enable/disable token refresh functionality
379
- `JWT_REFRESH_EXPIRATION_DELTA`: Maximum time allowed for token refresh
380
381
These settings control the behavior of token generation, validation, and refresh operations within the serializers.
382
383
## Module Variables
384
385
The serializers module defines several handler function references and the User model:
386
387
```python { .api }
388
User = get_user_model()
389
"""Reference to the configured Django User model."""
390
391
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
392
"""Function reference for generating JWT payloads from user instances."""
393
394
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
395
"""Function reference for encoding JWT tokens."""
396
397
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
398
"""Function reference for decoding JWT tokens."""
399
400
jwt_get_username_from_payload = api_settings.JWT_PAYLOAD_GET_USERNAME_HANDLER
401
"""Function reference for extracting username from JWT payload."""
402
```