1
1
from datetime import timedelta
2
+ import urllib .request , json
3
+
4
+ import jwt
2
5
3
6
from django .conf import settings
4
7
from django .utils import timezone
5
- from rest_framework .authentication import TokenAuthentication
8
+ from rest_framework .authentication import TokenAuthentication , BaseAuthentication
6
9
from rest_framework .exceptions import AuthenticationFailed
7
10
11
+ from .models import User
12
+
8
13
9
14
class ExpiringTokenAuthentication (TokenAuthentication ):
10
15
EXPIRATION_DURATION = timedelta (days = settings .AUTH_TOKEN_EXPIRES_AFTER_DAYS )
@@ -17,3 +22,55 @@ def authenticate_credentials(self, key):
17
22
raise AuthenticationFailed ("Token has expired." )
18
23
19
24
return user , token
25
+
26
+
27
+ class JWTAuthentication (BaseAuthentication ):
28
+ def authenticate (self , request ):
29
+ try :
30
+ raw_token = self .get_raw_jwt_token (request )
31
+ except ValueError :
32
+ return None
33
+ try :
34
+ validated_token = jwt .decode (
35
+ jwt = raw_token ,
36
+ algorithms = ["RS256" , "RS384" , "RS512" ],
37
+ key = self .get_public_key (),
38
+ options = {
39
+ "require" : [
40
+ "exp" ,
41
+ "nbf" ,
42
+ "aud" ,
43
+ "iss" ,
44
+ "sub" ,
45
+ ]
46
+ },
47
+ audience = settings .JWT_AUDIENCE ,
48
+ issuer = settings .JWT_ISSUER ,
49
+ )
50
+ except jwt .exceptions .PyJWTError as e :
51
+ raise AuthenticationFailed (f"Error validating JWT token: { e } " )
52
+ username = validated_token ["sub" ]
53
+ user = User .objects .get (username = username )
54
+ if not user :
55
+ raise AuthenticationFailed (f"No user found for username { username } " )
56
+
57
+ return user , validated_token
58
+
59
+ def get_public_key (self ):
60
+ with urllib .request .urlopen (settings .JWK_ENDPOINT ) as url :
61
+ jwk_data = json .load (url )
62
+ public_key = jwk_data ["keys" ][0 ]["n" ]
63
+ return public_key
64
+
65
+ def get_raw_jwt_token (self , request ):
66
+ """Raises ValueError if a jwt token could not be found"""
67
+ auth_header = request .META .get ("HTTP_AUTHORIZATION" , None )
68
+ if not auth_header :
69
+ raise ValueError ("No Authorization header found" )
70
+ try :
71
+ scheme , token = auth_header .split ()
72
+ except ValueError as e :
73
+ raise ValueError (f"Failed to parse Authorization header: { e } " )
74
+ if scheme .lower () != "bearer" :
75
+ raise ValueError (f"Invalid Authorization scheme: { scheme } " )
76
+ return token
0 commit comments