0
# OAuth2 Models
1
2
Django OAuth Toolkit provides comprehensive Django model classes for managing OAuth2 entities. These models handle applications, tokens, grants, and OIDC ID tokens with full ORM integration, validation, and admin interface support.
3
4
## Capabilities
5
6
### Application Management
7
8
OAuth2 client application registration and management with support for different client types and authorization grant types.
9
10
```python { .api }
11
class Application(AbstractApplication):
12
"""
13
OAuth2 client application model.
14
15
Attributes:
16
client_id (str): Unique client identifier
17
client_secret (str): Confidential client secret (hashed)
18
hash_client_secret (bool): Whether to hash client secret on save
19
name (str): Human-readable application name
20
user (User): Application owner
21
redirect_uris (str): Space-separated allowed redirect URIs
22
post_logout_redirect_uris (str): Space-separated OIDC logout URIs
23
client_type (str): 'confidential' or 'public'
24
authorization_grant_type (str): Grant type supported
25
skip_authorization (bool): Skip user consent screen
26
algorithm (str): OIDC signing algorithm
27
allowed_origins (str): CORS allowed origins
28
created (datetime): Application creation timestamp
29
updated (datetime): Last modification timestamp
30
"""
31
32
# Client types
33
CLIENT_CONFIDENTIAL = "confidential"
34
CLIENT_PUBLIC = "public"
35
CLIENT_TYPES = (
36
(CLIENT_CONFIDENTIAL, "Confidential"),
37
(CLIENT_PUBLIC, "Public"),
38
)
39
40
# Grant types
41
GRANT_AUTHORIZATION_CODE = "authorization-code"
42
GRANT_IMPLICIT = "implicit"
43
GRANT_PASSWORD = "password"
44
GRANT_CLIENT_CREDENTIALS = "client-credentials"
45
GRANT_OPENID_HYBRID = "openid-hybrid"
46
GRANT_TYPES = (
47
(GRANT_AUTHORIZATION_CODE, "Authorization code"),
48
(GRANT_IMPLICIT, "Implicit"),
49
(GRANT_PASSWORD, "Resource owner password-based"),
50
(GRANT_CLIENT_CREDENTIALS, "Client credentials"),
51
(GRANT_OPENID_HYBRID, "OpenID connect hybrid"),
52
)
53
54
# OIDC algorithms
55
NO_ALGORITHM = ""
56
RS256_ALGORITHM = "RS256"
57
HS256_ALGORITHM = "HS256"
58
ALGORITHM_TYPES = (
59
(NO_ALGORITHM, "No OIDC support"),
60
(RS256_ALGORITHM, "RSA with SHA-2 256"),
61
(HS256_ALGORITHM, "HMAC with SHA-2 256"),
62
)
63
64
objects = ApplicationManager()
65
66
def redirect_uri_allowed(self, uri: str) -> bool:
67
"""Check if URI is allowed for redirect"""
68
69
def post_logout_redirect_uri_allowed(self, uri: str) -> bool:
70
"""Check if URI is allowed for OIDC logout redirect"""
71
72
def origin_allowed(self, origin: str) -> bool:
73
"""Check if origin is allowed for CORS"""
74
75
def allows_grant_type(self, *grant_types: str) -> bool:
76
"""Check if application supports given grant types"""
77
78
def is_usable(self, request) -> bool:
79
"""Check if application can be used for request"""
80
81
@property
82
def default_redirect_uri(self) -> str:
83
"""Get default redirect URI if only one exists"""
84
85
@property
86
def jwk_key(self):
87
"""Get JWK key for OIDC signing"""
88
89
class ApplicationManager(models.Manager):
90
def get_by_natural_key(self, client_id: str) -> Application:
91
"""Get application by client ID"""
92
```
93
94
### Access Token Management
95
96
OAuth2 access tokens with scope validation, expiration checking, and revocation support.
97
98
```python { .api }
99
class AccessToken(AbstractAccessToken):
100
"""
101
OAuth2 access token model.
102
103
Attributes:
104
token (str): The access token value
105
token_checksum (str): SHA-256 checksum of token
106
user (User): Token owner
107
application (Application): Associated client application
108
expires (datetime): Token expiration time
109
scope (str): Space-separated granted scopes
110
source_refresh_token (RefreshToken): Source refresh token if any
111
id_token (IDToken): Associated OIDC ID token if any
112
"""
113
114
def is_valid(self, scopes=None) -> bool:
115
"""
116
Check if access token is valid.
117
118
Args:
119
scopes: Optional list of required scopes
120
121
Returns:
122
True if token is not expired and has required scopes
123
"""
124
125
def is_expired(self) -> bool:
126
"""Check if token has expired"""
127
128
def allow_scopes(self, scopes) -> bool:
129
"""
130
Check if token allows the provided scopes.
131
132
Args:
133
scopes: Iterable of scope names to check
134
135
Returns:
136
True if all scopes are allowed
137
"""
138
139
def revoke(self) -> None:
140
"""Revoke the access token by deleting it"""
141
142
@property
143
def scopes(self) -> dict:
144
"""Get dictionary of allowed scope names with descriptions"""
145
```
146
147
### Refresh Token Management
148
149
OAuth2 refresh tokens for obtaining new access tokens with revocation and family tracking.
150
151
```python { .api }
152
class RefreshToken(AbstractRefreshToken):
153
"""
154
OAuth2 refresh token model.
155
156
Attributes:
157
token (str): The refresh token value
158
user (User): Token owner
159
application (Application): Associated client application
160
access_token (AccessToken): Associated access token
161
token_family (UUID): Token family for rotation tracking
162
revoked (datetime): Revocation timestamp if revoked
163
"""
164
165
def revoke(self) -> None:
166
"""
167
Revoke refresh token and associated access token.
168
Handles atomic operations and prevents race conditions.
169
"""
170
```
171
172
### Authorization Grant Management
173
174
OAuth2 authorization grants for the authorization code flow with PKCE support.
175
176
```python { .api }
177
class Grant(AbstractGrant):
178
"""
179
OAuth2 authorization grant model.
180
181
Attributes:
182
user (User): User who authorized the grant
183
code (str): Authorization code
184
application (Application): Client application
185
expires (datetime): Grant expiration time
186
redirect_uri (str): Redirect URI for this grant
187
scope (str): Granted scopes
188
code_challenge (str): PKCE code challenge
189
code_challenge_method (str): PKCE challenge method ('plain' or 'S256')
190
nonce (str): OIDC nonce value
191
claims (str): OIDC claims parameter
192
"""
193
194
CODE_CHALLENGE_PLAIN = "plain"
195
CODE_CHALLENGE_S256 = "S256"
196
CODE_CHALLENGE_METHODS = (
197
(CODE_CHALLENGE_PLAIN, "plain"),
198
(CODE_CHALLENGE_S256, "S256")
199
)
200
201
def is_expired(self) -> bool:
202
"""Check if grant has expired"""
203
204
def redirect_uri_allowed(self, uri: str) -> bool:
205
"""Check if URI matches grant's redirect URI"""
206
```
207
208
### OIDC ID Token Management
209
210
OpenID Connect ID tokens for identity information with JWT token ID tracking.
211
212
```python { .api }
213
class IDToken(AbstractIDToken):
214
"""
215
OIDC ID token model.
216
217
Attributes:
218
jti (UUID): JWT Token ID for unique identification
219
user (User): Token subject
220
application (Application): Client application
221
expires (datetime): Token expiration time
222
scope (str): Token scopes
223
"""
224
225
def is_valid(self, scopes=None) -> bool:
226
"""Check if ID token is valid and has required scopes"""
227
228
def is_expired(self) -> bool:
229
"""Check if token has expired"""
230
231
def allow_scopes(self, scopes) -> bool:
232
"""Check if token allows the provided scopes"""
233
234
def revoke(self) -> None:
235
"""Revoke the ID token by deleting it"""
236
237
@property
238
def scopes(self) -> dict:
239
"""Get dictionary of allowed scope names with descriptions"""
240
```
241
242
### Model Factory Functions
243
244
Functions to get the active model classes, supporting Django's swappable model system.
245
246
```python { .api }
247
def get_application_model():
248
"""Return the Application model class active in this project"""
249
250
def get_access_token_model():
251
"""Return the AccessToken model class active in this project"""
252
253
def get_refresh_token_model():
254
"""Return the RefreshToken model class active in this project"""
255
256
def get_grant_model():
257
"""Return the Grant model class active in this project"""
258
259
def get_id_token_model():
260
"""Return the IDToken model class active in this project"""
261
```
262
263
### Token Cleanup Functions
264
265
Utility functions for managing token lifecycle and cleanup.
266
267
```python { .api }
268
def clear_expired() -> None:
269
"""
270
Remove all expired tokens and grants from the database.
271
Handles batch deletion to avoid memory issues with large datasets.
272
Processes refresh tokens, access tokens, ID tokens, and grants.
273
"""
274
```
275
276
### Validation Utilities
277
278
Helper functions for URI and origin validation.
279
280
```python { .api }
281
def redirect_to_uri_allowed(uri: str, allowed_uris: list) -> bool:
282
"""
283
Check if URI can be redirected to based on allowed URIs.
284
Handles exact matches and RFC 8252 loopback IP rules.
285
286
Args:
287
uri: URI to validate
288
allowed_uris: List of allowed redirect URIs
289
290
Returns:
291
True if redirect is allowed
292
"""
293
294
def is_origin_allowed(origin: str, allowed_origins: list) -> bool:
295
"""
296
Check if origin is allowed based on CORS configuration.
297
298
Args:
299
origin: Origin URI to validate
300
allowed_origins: List of allowed origin URIs
301
302
Returns:
303
True if origin is allowed
304
"""
305
```
306
307
## Model Admin Helpers
308
309
Factory functions for retrieving active admin classes for OAuth2 models. These functions return the admin classes configured through Django settings.
310
311
```python { .api }
312
def get_application_admin_class():
313
"""Return the Application admin class that is active in this project."""
314
315
def get_access_token_admin_class():
316
"""Return the AccessToken admin class that is active in this project."""
317
318
def get_grant_admin_class():
319
"""Return the Grant admin class that is active in this project."""
320
321
def get_id_token_admin_class():
322
"""Return the IDToken admin class that is active in this project."""
323
324
def get_refresh_token_admin_class():
325
"""Return the RefreshToken admin class that is active in this project."""
326
```
327
328
## Usage Examples
329
330
### Creating Applications
331
332
```python
333
from oauth2_provider.models import Application
334
335
# Confidential web application
336
web_app = Application.objects.create(
337
name="My Web Application",
338
client_type=Application.CLIENT_CONFIDENTIAL,
339
authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
340
redirect_uris="http://localhost:8000/callback/",
341
)
342
343
# Public mobile application
344
mobile_app = Application.objects.create(
345
name="My Mobile App",
346
client_type=Application.CLIENT_PUBLIC,
347
authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
348
redirect_uris="myapp://callback/",
349
)
350
```
351
352
### Working with Tokens
353
354
```python
355
from oauth2_provider.models import AccessToken, get_access_token_model
356
357
# Check token validity
358
token = AccessToken.objects.get(token="your-token-here")
359
if token.is_valid(['read', 'write']):
360
print("Token is valid for read/write operations")
361
362
# Revoke tokens
363
token.revoke()
364
365
# Clean up expired tokens
366
from oauth2_provider.models import clear_expired
367
clear_expired()
368
```
369
370
### Model Relationships
371
372
```python
373
# Access related objects
374
application = Application.objects.get(client_id="your-client-id")
375
tokens = application.accesstoken_set.filter(expires__gt=timezone.now())
376
377
# Get user's applications
378
user_apps = Application.objects.filter(user=request.user)
379
380
# Get user's authorized tokens
381
user_tokens = AccessToken.objects.filter(user=request.user)
382
```