44from functools import wraps
55import json
66from os import environ as env
7+ from typing import Dict
8+
79from six .moves .urllib .request import urlopen
810
911from dotenv import load_dotenv , find_dotenv
10- from flask import Flask , request , jsonify , _request_ctx_stack
12+ from flask import Flask , request , jsonify , _request_ctx_stack , Response
1113from flask_cors import cross_origin
1214from jose import jwt
1315
2224
2325# Format error response and append status code.
2426class AuthError (Exception ):
25- def __init__ (self , error , status_code ):
27+ def __init__ (self , error : Dict [ str , str ], status_code : int ):
2628 self .error = error
2729 self .status_code = status_code
2830
2931
3032@APP .errorhandler (AuthError )
31- def handle_auth_error (ex ) :
33+ def handle_auth_error (ex : AuthError ) -> Response :
3234 response = jsonify (ex .error )
3335 response .status_code = ex .status_code
3436 return response
3537
3638
37- def get_token_auth_header ():
39+ def get_token_auth_header () -> str :
3840 """Obtains the access token from the Authorization Header
3941 """
4042 auth = request .headers .get ("Authorization" , None )
4143 if not auth :
4244 raise AuthError ({"code" : "authorization_header_missing" ,
43- "description" :
44- "Authorization header is expected" }, 401 )
45+ "description" :
46+ "Authorization header is expected" }, 401 )
4547
4648 parts = auth .split ()
4749
4850 if parts [0 ].lower () != "bearer" :
4951 raise AuthError ({"code" : "invalid_header" ,
50- "description" :
51- "Authorization header must start with"
52- " Bearer" }, 401 )
52+ "description" :
53+ "Authorization header must start with"
54+ " Bearer" }, 401 )
5355 elif len (parts ) == 1 :
5456 raise AuthError ({"code" : "invalid_header" ,
55- "description" : "Token not found" }, 401 )
57+ "description" : "Token not found" }, 401 )
5658 elif len (parts ) > 2 :
5759 raise AuthError ({"code" : "invalid_header" ,
58- "description" :
59- "Authorization header must be"
60- " Bearer token" }, 401 )
60+ "description" :
61+ "Authorization header must be"
62+ " Bearer token" }, 401 )
6163
6264 token = parts [1 ]
6365 return token
6466
6567
66- def requires_scope (required_scope ) :
68+ def requires_scope (required_scope : str ) -> bool :
6769 """Determines if the required scope is present in the access token
6870 Args:
6971 required_scope (str): The scope required to access the resource
@@ -81,23 +83,24 @@ def requires_scope(required_scope):
8183def requires_auth (f ):
8284 """Determines if the access token is valid
8385 """
86+
8487 @wraps (f )
8588 def decorated (* args , ** kwargs ):
8689 token = get_token_auth_header ()
87- jsonurl = urlopen ("https://" + AUTH0_DOMAIN + "/.well-known/jwks.json" )
90+ jsonurl = urlopen ("https://" + AUTH0_DOMAIN + "/.well-known/jwks.json" )
8891 jwks = json .loads (jsonurl .read ())
8992 try :
9093 unverified_header = jwt .get_unverified_header (token )
9194 except jwt .JWTError :
9295 raise AuthError ({"code" : "invalid_header" ,
93- "description" :
94- "Invalid header. "
95- "Use an RS256 signed JWT Access Token" }, 401 )
96+ "description" :
97+ "Invalid header. "
98+ "Use an RS256 signed JWT Access Token" }, 401 )
9699 if unverified_header ["alg" ] == "HS256" :
97100 raise AuthError ({"code" : "invalid_header" ,
98- "description" :
99- "Invalid header. "
100- "Use an RS256 signed JWT Access Token" }, 401 )
101+ "description" :
102+ "Invalid header. "
103+ "Use an RS256 signed JWT Access Token" }, 401 )
101104 rsa_key = {}
102105 for key in jwks ["keys" ]:
103106 if key ["kid" ] == unverified_header ["kid" ]:
@@ -115,26 +118,27 @@ def decorated(*args, **kwargs):
115118 rsa_key ,
116119 algorithms = ALGORITHMS ,
117120 audience = API_IDENTIFIER ,
118- issuer = "https://" + AUTH0_DOMAIN + "/"
121+ issuer = "https://" + AUTH0_DOMAIN + "/"
119122 )
120123 except jwt .ExpiredSignatureError :
121124 raise AuthError ({"code" : "token_expired" ,
122- "description" : "token is expired" }, 401 )
125+ "description" : "token is expired" }, 401 )
123126 except jwt .JWTClaimsError :
124127 raise AuthError ({"code" : "invalid_claims" ,
125- "description" :
126- "incorrect claims,"
127- " please check the audience and issuer" }, 401 )
128+ "description" :
129+ "incorrect claims,"
130+ " please check the audience and issuer" }, 401 )
128131 except Exception :
129132 raise AuthError ({"code" : "invalid_header" ,
130- "description" :
131- "Unable to parse authentication"
132- " token." }, 401 )
133+ "description" :
134+ "Unable to parse authentication"
135+ " token." }, 401 )
133136
134137 _request_ctx_stack .top .current_user = payload
135138 return f (* args , ** kwargs )
136139 raise AuthError ({"code" : "invalid_header" ,
137- "description" : "Unable to find appropriate key" }, 401 )
140+ "description" : "Unable to find appropriate key" }, 401 )
141+
138142 return decorated
139143
140144
0 commit comments