or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

drf-integration.mdindex.mdmanagement-commands.mdmanagement-views.mdmodels.mdoauth2-endpoints.mdoidc.mdsettings.mdview-protection.md

view-protection.mddocs/

0

# View Protection

1

2

Django OAuth Toolkit provides decorators and middleware for protecting Django views with OAuth2 authentication and scope-based authorization. These tools integrate seamlessly with Django's view system and provide flexible access control.

3

4

## Capabilities

5

6

### Protected Resource Decorator

7

8

Basic OAuth2 authentication decorator that protects views by requiring valid access tokens.

9

10

```python { .api }

11

def protected_resource(scopes=None, validator_cls=OAuth2Validator, server_cls=Server):

12

"""

13

Decorator to protect views with OAuth2 authentication.

14

15

Args:

16

scopes: List of required OAuth2 scopes (optional)

17

validator_cls: Custom OAuth2 validator class

18

server_cls: Custom OAuth2 server class

19

20

Returns:

21

Decorated view function that requires OAuth2 authentication

22

23

Usage:

24

@protected_resource()

25

def my_view(request):

26

# Access token required to reach here

27

user = request.resource_owner # User from token or None

28

return JsonResponse({'user': user.username if user else None})

29

30

@protected_resource(scopes=['read'])

31

def read_data(request):

32

# Requires 'read' scope

33

return JsonResponse({'data': 'protected content'})

34

"""

35

```

36

37

### Read/Write Protected Resource Decorator

38

39

OAuth2 decorator with automatic read/write scope assignment based on HTTP method.

40

41

```python { .api }

42

def rw_protected_resource(scopes=None, validator_cls=OAuth2Validator, server_cls=Server):

43

"""

44

Decorator that automatically assigns read/write scopes based on HTTP method.

45

GET, HEAD, OPTIONS methods require 'read' scope.

46

All other methods require 'write' scope.

47

48

Args:

49

scopes: Additional required scopes beyond read/write

50

validator_cls: Custom OAuth2 validator class

51

server_cls: Custom OAuth2 server class

52

53

Returns:

54

Decorated view function with automatic scope assignment

55

56

Usage:

57

@rw_protected_resource()

58

def api_endpoint(request):

59

# GET requests need 'read' scope

60

# POST/PUT/DELETE requests need 'write' scope

61

if request.method == 'POST':

62

return JsonResponse({'created': True})

63

return JsonResponse({'data': 'content'})

64

"""

65

```

66

67

### Generic Protected Views

68

69

Class-based views that provide OAuth2 protection with various scope configurations.

70

71

```python { .api }

72

class ProtectedResourceView(View):

73

"""

74

Basic OAuth2 protected view requiring valid access token.

75

76

Attributes:

77

required_scopes: List of required OAuth2 scopes

78

raise_exception: Whether to raise exception on auth failure

79

server_class: OAuth2 server class to use

80

validator_class: OAuth2 validator class to use

81

"""

82

83

required_scopes = []

84

raise_exception = False

85

server_class = Server

86

validator_class = OAuth2Validator

87

88

class ScopedProtectedResourceView(ProtectedResourceView):

89

"""

90

OAuth2 protected view with specific scope requirements.

91

Subclasses must define required_scopes attribute.

92

"""

93

94

required_scopes = None # Must be overridden

95

96

class ReadWriteScopedResourceView(ProtectedResourceView):

97

"""

98

OAuth2 protected view with automatic read/write scope assignment.

99

Safe methods (GET, HEAD, OPTIONS) require read scope.

100

Unsafe methods require write scope.

101

"""

102

103

def get_scopes(self, request):

104

"""

105

Get required scopes based on request method.

106

107

Returns:

108

List of scopes required for this request

109

"""

110

111

class ClientProtectedResourceView(ProtectedResourceView):

112

"""

113

OAuth2 protected view for client credentials flow.

114

Designed for server-to-server authentication.

115

"""

116

117

class ClientProtectedScopedResourceView(ClientProtectedResourceView):

118

"""

119

OAuth2 protected view for client credentials with specific scopes.

120

"""

121

122

required_scopes = None # Must be overridden

123

```

124

125

### OAuth2 Token Middleware

126

127

Django middleware that adds OAuth2 token information to requests.

128

129

```python { .api }

130

class OAuth2TokenMiddleware:

131

"""

132

Middleware that processes OAuth2 tokens and adds token info to request.

133

134

Adds the following attributes to HttpRequest:

135

- oauth2_error: Dict containing OAuth2 error information if any

136

- resource_owner: User associated with the token (if valid)

137

138

Should be added to MIDDLEWARE setting in Django configuration.

139

"""

140

141

def __init__(self, get_response):

142

"""Initialize middleware with Django response handler"""

143

144

def __call__(self, request):

145

"""Process request and add OAuth2 token information"""

146

```

147

148

## Usage Examples

149

150

### Basic View Protection

151

152

```python

153

from oauth2_provider.decorators import protected_resource

154

from django.http import JsonResponse

155

156

@protected_resource()

157

def protected_api(request):

158

"""View requiring any valid OAuth2 token"""

159

return JsonResponse({

160

'message': 'Hello authenticated user!',

161

'user': request.resource_owner.username if request.resource_owner else 'Anonymous'

162

})

163

164

@protected_resource(scopes=['read'])

165

def read_only_api(request):

166

"""View requiring 'read' scope"""

167

return JsonResponse({'data': 'This is read-only data'})

168

169

@protected_resource(scopes=['write'])

170

def write_api(request):

171

"""View requiring 'write' scope"""

172

if request.method == 'POST':

173

return JsonResponse({'created': True})

174

return JsonResponse({'error': 'Method not allowed'}, status=405)

175

```

176

177

### Read/Write Scope Views

178

179

```python

180

from oauth2_provider.decorators import rw_protected_resource

181

182

@rw_protected_resource()

183

def auto_scope_api(request):

184

"""

185

Automatically assigns scopes:

186

- GET/HEAD/OPTIONS: requires 'read' scope

187

- POST/PUT/DELETE/PATCH: requires 'write' scope

188

"""

189

if request.method == 'GET':

190

return JsonResponse({'data': 'Retrieved data'})

191

elif request.method == 'POST':

192

return JsonResponse({'message': 'Data created'})

193

elif request.method == 'PUT':

194

return JsonResponse({'message': 'Data updated'})

195

elif request.method == 'DELETE':

196

return JsonResponse({'message': 'Data deleted'})

197

198

@rw_protected_resource(scopes=['admin'])

199

def admin_api(request):

200

"""Requires both read/write scopes AND admin scope"""

201

return JsonResponse({'message': 'Admin operation completed'})

202

```

203

204

### Class-Based Protected Views

205

206

```python

207

from oauth2_provider.views.generic import (

208

ProtectedResourceView,

209

ScopedProtectedResourceView,

210

ReadWriteScopedResourceView

211

)

212

from django.http import JsonResponse

213

214

class BasicProtectedView(ProtectedResourceView):

215

"""Basic OAuth2 protected view"""

216

217

def get(self, request):

218

return JsonResponse({

219

'user': request.resource_owner.username if request.resource_owner else None

220

})

221

222

class AdminOnlyView(ScopedProtectedResourceView):

223

"""View requiring admin scope"""

224

required_scopes = ['admin']

225

226

def get(self, request):

227

return JsonResponse({'message': 'Admin access granted'})

228

229

class AutoScopeView(ReadWriteScopedResourceView):

230

"""View with automatic read/write scope assignment"""

231

232

def get(self, request):

233

# Requires 'read' scope

234

return JsonResponse({'data': 'Read operation'})

235

236

def post(self, request):

237

# Requires 'write' scope

238

return JsonResponse({'message': 'Write operation'})

239

```

240

241

### Custom Authentication Logic

242

243

```python

244

from oauth2_provider.decorators import protected_resource

245

from oauth2_provider.oauth2_validators import OAuth2Validator

246

from oauthlib.oauth2 import Server

247

248

class CustomValidator(OAuth2Validator):

249

"""Custom OAuth2 validator with additional business logic"""

250

251

def validate_scopes(self, client_id, scopes, client, request, *args, **kwargs):

252

# Custom scope validation logic

253

return super().validate_scopes(client_id, scopes, client, request, *args, **kwargs)

254

255

@protected_resource(

256

scopes=['api'],

257

validator_cls=CustomValidator,

258

server_cls=Server

259

)

260

def custom_protected_view(request):

261

"""View with custom validator and server classes"""

262

return JsonResponse({'message': 'Custom authentication successful'})

263

```

264

265

### Middleware Configuration

266

267

```python

268

# settings.py

269

MIDDLEWARE = [

270

'django.middleware.security.SecurityMiddleware',

271

'django.contrib.sessions.middleware.SessionMiddleware',

272

'corsheaders.middleware.CorsMiddleware',

273

'django.middleware.common.CommonMiddleware',

274

'django.middleware.csrf.CsrfViewMiddleware',

275

'oauth2_provider.middleware.OAuth2TokenMiddleware', # Add OAuth2 middleware

276

'django.contrib.auth.middleware.AuthenticationMiddleware',

277

'django.contrib.messages.middleware.MessageMiddleware',

278

'django.middleware.clickjacking.XFrameOptionsMiddleware',

279

]

280

```

281

282

### Error Handling

283

284

```python

285

from oauth2_provider.decorators import protected_resource

286

from django.http import JsonResponse, HttpResponseForbidden

287

288

@protected_resource(scopes=['read'])

289

def error_handling_view(request):

290

"""View demonstrating error handling"""

291

try:

292

# Your protected logic here

293

return JsonResponse({'data': 'success'})

294

except Exception as e:

295

return JsonResponse({'error': str(e)}, status=500)

296

297

# OAuth2 errors are automatically handled:

298

# - Missing token: HTTP 401 Unauthorized

299

# - Invalid token: HTTP 401 Unauthorized

300

# - Insufficient scopes: HTTP 403 Forbidden

301

# - Expired token: HTTP 401 Unauthorized

302

```

303

304

### Integration with Custom User Models

305

306

```python

307

from oauth2_provider.decorators import protected_resource

308

from django.contrib.auth import get_user_model

309

310

User = get_user_model()

311

312

@protected_resource()

313

def user_profile_view(request):

314

"""Access custom user model through OAuth2 token"""

315

user = request.resource_owner

316

if user:

317

return JsonResponse({

318

'id': user.id,

319

'username': user.username,

320

'email': user.email,

321

# Access custom user fields

322

'custom_field': getattr(user, 'custom_field', None)

323

})

324

return JsonResponse({'error': 'No user found'}, status=400)

325

```