Skip to content

Instantly share code, notes, and snippets.

@spencerkittleson
Last active March 21, 2024 18:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save spencerkittleson/f717d90c8035c701e6127e1b3ce10c57 to your computer and use it in GitHub Desktop.
Save spencerkittleson/f717d90c8035c701e6127e1b3ce10c57 to your computer and use it in GitHub Desktop.
Validate a JWT token is from a configured issuer
import requests
import json
import jwt
from dotenv import dotenv_values
def get_json(endpoint: str):
response = requests.get(endpoint)
response.raise_for_status()
return json.loads(response.content)
def verify_jwt(token, issuer, discovery=None):
"""Only public key verification is needed here"""
try:
# Decode the JWT without verifying the signature
unvalidated_decoded_token = jwt.decode(
token, options={"verify_signature": False})
# Check if the issuer matches
if unvalidated_decoded_token['iss'] != issuer:
return False, "Issuer mismatch"
# Get the default JWKS token.
jwks_keys = get_json(discovery['jwks_uri'])['keys']
filtered_keys = [key for key in jwks_keys if key.get(
'kid') in 'default' or key.get('kid') is None]
key = None
if filtered_keys:
key = filtered_keys[0]
else:
return False, "No kid that is default or None"
# Now verify the given token
jwt_from_default = jwt.PyJWK(key)
header = jwt.get_unverified_header(token)
jwt.decode(token, jwt_from_default.key, [
header["alg"]], options={'verify_signature': True}, audience=unvalidated_decoded_token['aud'])
return True, "JWT is valid"
except jwt.ExpiredSignatureError:
return False, "JWT has expired"
except jwt.InvalidIssuerError:
return False, "Invalid issuer"
except jwt.InvalidTokenError as e:
return False, f"Invalid token: {str(e)}"
except Exception as e:
return False, f"An error occurred: {str(e)}"
if __name__ == '__main__':
config = dotenv_values('.env')
discovery = None
# Discovery endpoint lookup
if config['discovery'] is not None and config['discovery'] != '':
discovery = get_json(config['discovery'])
# Compare issuer in configuration against well known issuer
if discovery['issuer'] != config['issuer']:
raise Exception('Issuer configuration mismatched')
# Validate a JWT against the known configured issuer
valid, reason = verify_jwt(config['token'], config['issuer'], discovery)
if valid:
print('Token is good! Extract the user info.')
else:
raise Exception(f'Issuer configuration mismatched. {reason}')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment