def verify_jwt(access_token, refresh_token, jwk_url, alg, aud, iss): jwks_client = PyJWKClient(jwk_url) access_key = jwks_client.get_signing_key_from_jwt(access_token) refresh_key = jwks_client.get_signing_key_from_jwt(refresh_token) try: jwt.decode(access_token, access_key.key, algorithms=alg, audience=aud, issuer=iss) jwt.decode(refresh_token, refresh_key.key, algorithms=alg, issuer=iss) except jwt.PyJWTError: return False return True
def verify_token(token): url = "https://everymovecounts.b2clogin.com/everymovecounts.onmicrosoft.com/discovery/v2.0/keys?p=b2c_1_emcsignin" jwks_client = PyJWKClient(url) decoded_token = '' retdict = {} try: signing_key = jwks_client.get_signing_key_from_jwt(token) data = jwt.decode(token, signing_key.key, algorithms=["RS256"], audience="08ebc94f-55a7-45bf-9586-56f69290af27", options={ "verify_exp": True, "require": ["exp", "iss", "sub"] }) decoded_token = data except Exception as e: retdict['error'] = 'Error in validating token :' + ' ' + str(e) else: retdict = {} #print (decoded_token) retdict['emails'] = decoded_token.pop('emails') retdict['sub'] = decoded_token.pop('sub') retdict['given_name'] = decoded_token.pop('given_name') retdict['extension_StravaID'] = decoded_token.pop('extension_StravaID') return retdict
def verify_id_token(id_token: str, bundle_id=None) -> dict: if bundle_id is None: bundle_id = APPLE_SIGN_IN_AUD[0] if bundle_id not in APPLE_SIGN_IN_AUD: raise falcon.HTTPForbidden(description="Not allow bundle id.") jwt_header = jwt.get_unverified_header(id_token) # get kid to select public key kid = jwt_header.get("kid", None) if kid is None: raise falcon.HTTPUnauthorized( description= "Not found kid from your id_token, check your token is by apple sign in." ) jwks_client = PyJWKClient(APPLE_AUTH_KEYS_URL) signing_key = jwks_client.get_signing_key_from_jwt(id_token) jwt_decode = jwt.decode( id_token, signing_key.key, algorithms=["RS256"], audience=bundle_id, options={"verify_exp": False}, ) return jwt_decode
def test_get_signing_key_from_jwt(self, mocked_response): token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik5FRTFRVVJCT1RNNE16STVSa0ZETlRZeE9UVTFNRGcyT0Rnd1EwVXpNVGsxUWpZeVJrUkZRdyJ9.eyJpc3MiOiJodHRwczovL2Rldi04N2V2eDlydS5hdXRoMC5jb20vIiwic3ViIjoiYVc0Q2NhNzl4UmVMV1V6MGFFMkg2a0QwTzNjWEJWdENAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vZXhwZW5zZXMtYXBpIiwiaWF0IjoxNTcyMDA2OTU0LCJleHAiOjE1NzIwMDY5NjQsImF6cCI6ImFXNENjYTc5eFJlTFdVejBhRTJINmtEME8zY1hCVnRDIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.PUxE7xn52aTCohGiWoSdMBZGiYAHwE5FYie0Y1qUT68IHSTXwXVd6hn02HTah6epvHHVKA2FqcFZ4GGv5VTHEvYpeggiiZMgbxFrmTEY0csL6VNkX1eaJGcuehwQCRBKRLL3zKmA5IKGy5GeUnIbpPHLHDxr-GXvgFzsdsyWlVQvPX2xjeaQ217r2PtxDeqjlf66UYl6oY6AqNS8DH3iryCvIfCcybRZkc_hdy-6ZMoKT6Piijvk_aXdm7-QQqKJFHLuEqrVSOuBqqiNfVrG27QzAPuPOxvfXTVLXL2jek5meH6n-VWgrBdoMFH93QEszEDowDAEhQPHVs0xj7SIzA" url = "https://dev-87evx9ru.auth0.com/.well-known/jwks.json" with mocked_response(RESPONSE_DATA): jwks_client = PyJWKClient(url) signing_key = jwks_client.get_signing_key_from_jwt(token) data = jwt.decode( token, signing_key.key, algorithms=["RS256"], audience="https://expenses-api", options={"verify_exp": False}, ) assert data == { "iss": "https://dev-87evx9ru.auth0.com/", "sub": "aW4Cca79xReLWUz0aE2H6kD0O3cXBVtC@clients", "aud": "https://expenses-api", "iat": 1572006954, "exp": 1572006964, "azp": "aW4Cca79xReLWUz0aE2H6kD0O3cXBVtC", "gty": "client-credentials", }
def validated_token(token, verify=True): """Validate a token and return decoded token.""" url = ( requests.get( config.oauth.google_openid_config_uri(default=DEFAULT_GOOGLE_OPENID_CFG_URI) ) .json() .get( config.oauth.google_openid_jkws_key( default=DEFAULT_GOOGLE_OPENID_CFG_JWKS_KEY ) ) ) logger.info("JWK url is %s", url) jwks_client = PyJWKClient(url) signing_key = jwks_client.get_signing_key_from_jwt(token) data = jwt.decode( token, signing_key.key, algorithms=["RS256"], audience=config.oauth.audience(default=DEFAULT_AUDIENCE, cast=split_list), options={"verify_signature": verify}, ) return data
def get_credentials(): expected_errors = { KeyError: WRONG_PAYLOAD_STRUCTURE, AssertionError: JWKS_HOST_MISSING, InvalidSignatureError: WRONG_KEY, DecodeError: WRONG_JWT_STRUCTURE, MissingRequiredClaimError: WRONG_PAYLOAD_STRUCTURE, InvalidAudienceError: WRONG_AUDIENCE, PyJWKClientError: KID_NOT_FOUND, URLError: WRONG_JWKS_HOST, HTTPError: WRONG_JWKS_HOST } try: token = get_auth_token() jwks_host = jwt.decode(token, options={ 'verify_signature': False }).get('jwks_host') assert jwks_host jwks_client = PyJWKClient(f'https://{jwks_host}/.well-known/jwks') signing_key = jwks_client.get_signing_key_from_jwt(token) aud = request.url_root payload = jwt.decode(token, signing_key.key, algorithms=['RS256'], audience=[aud.rstrip('/')]) current_app.config['SERVER_IP'] = payload['SERVER_IP'] set_ctr_entities_limit(payload) return payload['user'], payload['pass'] except tuple(expected_errors) as error: raise AuthorizationError(expected_errors[error.__class__])
async def test_full_flow(self) -> None: key = await random_key() uuid_identifier = uuid4() # Register a new key # This is done using direct json since KeyRequest.dump doesn't dump key (on purpose) request = RegisterKeyRequest(key, uuid4()) response = await self.client.post( "/register_key", json=self.register_key_request_schema.dump(request)) assert response.status == HTTPStatus.CREATED # Check that the key was registered request2 = KeyRequest(key) response = await self.client.post( "/is_key_registered", json=self.key_request_schema.dump(request2)) assert response.status == HTTPStatus.OK # Authenticate and get access + refres tokens request = self.auth_request_schema.dump( AuthRequest(key=key, identifier=uuid_identifier)) response = await self.client.post("/authenticate", json=request) assert response.status == HTTPStatus.OK response_json = await response.json() # Check access token is valid request = self.jwt_validate_request_schema.dump( JWTValidateRequest(jwt=response_json["jwt"])) response = await self.client.post("/validate", json=request) assert response.status == HTTPStatus.OK # Use refresh token to create a new access token request = self.refresh_request_schema.dump( RefreshRequest(refresh_token=response_json["refresh_token"], identifier=uuid_identifier)) response = await self.client.post("/refresh", json=request) assert response.status == HTTPStatus.OK response_json = await response.json() # Check that new access token is also valid token = response_json["jwt"] request = self.jwt_validate_request_schema.dump( JWTValidateRequest(jwt=token)) response = await self.client.post("/validate", json=request) assert response.status == HTTPStatus.OK # Test JWKS response = await self.client.get("/jwks") assert response.status == HTTPStatus.OK response_json = await response.json() jwks_client = PyJWKClient("") jwks_client.fetch_data = MagicMock( return_value=response_json) # type: ignore assert jwks_client.get_signing_key_from_jwt(token)
def _get_public_key(self): if self.header["alg"][:2] == "RS": try: wk_res = requests.get(self.payload["iss"] + "/.well-known/openid-configuration", verify=False) jwks_uri = wk_res.json()["jwks_uri"] jwks_client = PyJWKClient(jwks_uri) return jwks_client.get_signing_key_from_jwt( self.encoded).key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) except Exception as ex: self.errors.append("Error getting public Key: {0}".format( str(ex))) return None
async def query_jwks(): #dump('NO CACHE, TRY CONSUMER: ' + consumer_name) # Get default or overridden jwks_url jwks_url = consumer.jwks_url or default_jwks_url self.log.debug( 'Verifying JWT via JWKS URL {}'.format( jwks_url)) # Get signing_key from jwks jwks_client = PyJWKClient(jwks_url) signing_key = jwks_client.get_signing_key_from_jwt( token) return Dict( decode(jwt=token, key=signing_key.key, audience=consumer.aud, algorithms=consumer.algorithms))
def validate_id_token(identity_token): identity_token = base64.b64decode(identity_token) jwk_client = PyJWKClient('https://appleid.apple.com/auth/keys') signing_key = jwk_client.get_signing_key_from_jwt(identity_token) try: data = jwt.decode(identity_token, signing_key.key, algorithms=['RS256'], audience=os.environ['BUNDLE_ID'], issuer='https://appleid.apple.com', options={ 'verify_aud': True, 'verify_exp': True, 'verify_iss': True }) except exceptions.InvalidTokenError as error: return False return True
def get_current_user_info(jwt_assertion: str): if os.getenv("TEST_USER", False): return { "aud": [], "email": "*****@*****.**", "exp": 1548134702, "iat": 1548134702, "iss": "localhost.com", "nbf": 1548134702, "sub": "localhost/testuser", } url = os.environ["JWK_ENDPOINT"] jwks_client = PyJWKClient(url) signing_key = jwks_client.get_signing_key_from_jwt(jwt_assertion) return jwt.decode( jwt_assertion, signing_key.key, algorithms=["ES256"], options={ "verify_aud": False, }, )
class TokenBackend: def __init__( self, algorithm, signing_key=None, verifying_key=None, audience=None, issuer=None, jwk_url: str = None, leeway=0, ): self._validate_algorithm(algorithm) self.algorithm = algorithm self.signing_key = signing_key self.audience = audience self.issuer = issuer self.jwks_client = PyJWKClient(jwk_url) if jwk_url else None self.leeway = leeway if algorithm.startswith("HS"): self.verifying_key = signing_key else: self.verifying_key = verifying_key def _validate_algorithm(self, algorithm): """ Ensure that the nominated algorithm is recognized, and that cryptography is installed for those algorithms that require it """ if algorithm not in ALLOWED_ALGORITHMS: raise TokenBackendError( format_lazy(_("Unrecognized algorithm type '{}'"), algorithm)) if algorithm in algorithms.requires_cryptography and not algorithms.has_crypto: raise TokenBackendError( format_lazy( _("You must have cryptography installed to use {}."), algorithm)) def get_verifying_key(self, token): if self.algorithm.startswith("HS"): return self.signing_key if self.jwks_client: return self.jwks_client.get_signing_key_from_jwt(token).key return self.verifying_key def encode(self, payload): """ Returns an encoded token for the given payload dictionary. """ jwt_payload = payload.copy() if self.audience is not None: jwt_payload['aud'] = self.audience if self.issuer is not None: jwt_payload['iss'] = self.issuer token = jwt.encode(jwt_payload, self.signing_key, algorithm=self.algorithm) if isinstance(token, bytes): # For PyJWT <= 1.7.1 return token.decode('utf-8') # For PyJWT >= 2.0.0a1 return token def decode(self, token, verify=True): """ Performs a validation of the given token and returns its payload dictionary. Raises a `TokenBackendError` if the token is malformed, if its signature check fails, or if its 'exp' claim indicates it has expired. """ try: return jwt.decode( token, self.get_verifying_key(token), algorithms=[self.algorithm], audience=self.audience, issuer=self.issuer, leeway=self.leeway, options={ 'verify_aud': self.audience is not None, 'verify_signature': verify, }, ) except InvalidAlgorithmError as ex: raise TokenBackendError(_('Invalid algorithm specified')) from ex except InvalidTokenError: raise TokenBackendError(_('Token is invalid or expired'))
class TokenBackend: def __init__( self, algorithm, signing_key=None, verifying_key="", audience=None, issuer=None, jwk_url: str = None, leeway: Union[float, int, timedelta] = None, ): self._validate_algorithm(algorithm) self.algorithm = algorithm self.signing_key = signing_key self.verifying_key = verifying_key self.audience = audience self.issuer = issuer if JWK_CLIENT_AVAILABLE: self.jwks_client = PyJWKClient(jwk_url) if jwk_url else None else: self.jwks_client = None self.leeway = leeway def _validate_algorithm(self, algorithm): """ Ensure that the nominated algorithm is recognized, and that cryptography is installed for those algorithms that require it """ if algorithm not in ALLOWED_ALGORITHMS: raise TokenBackendError( format_lazy(_("Unrecognized algorithm type '{}'"), algorithm)) if algorithm in algorithms.requires_cryptography and not algorithms.has_crypto: raise TokenBackendError( format_lazy( _("You must have cryptography installed to use {}."), algorithm)) def get_leeway(self) -> timedelta: if self.leeway is None: return timedelta(seconds=0) elif isinstance(self.leeway, (int, float)): return timedelta(seconds=self.leeway) elif isinstance(self.leeway, timedelta): return self.leeway else: raise TokenBackendError( format_lazy( _("Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." ), type(self.leeway), )) def get_verifying_key(self, token): if self.algorithm.startswith("HS"): return self.signing_key if self.jwks_client: return self.jwks_client.get_signing_key_from_jwt(token).key return self.verifying_key def encode(self, payload): """ Returns an encoded token for the given payload dictionary. """ jwt_payload = payload.copy() if self.audience is not None: jwt_payload["aud"] = self.audience if self.issuer is not None: jwt_payload["iss"] = self.issuer token = jwt.encode(jwt_payload, self.signing_key, algorithm=self.algorithm) if isinstance(token, bytes): # For PyJWT <= 1.7.1 return token.decode("utf-8") # For PyJWT >= 2.0.0a1 return token def decode(self, token, verify=True): """ Performs a validation of the given token and returns its payload dictionary. Raises a `TokenBackendError` if the token is malformed, if its signature check fails, or if its 'exp' claim indicates it has expired. """ try: return jwt.decode( token, self.get_verifying_key(token), algorithms=[self.algorithm], audience=self.audience, issuer=self.issuer, leeway=self.get_leeway(), options={ "verify_aud": self.audience is not None, "verify_signature": verify, }, ) except InvalidAlgorithmError as ex: raise TokenBackendError(_("Invalid algorithm specified")) from ex except InvalidTokenError: raise TokenBackendError(_("Token is invalid or expired"))
def verify_jwt_using_jwks(self, token, jwks_url, audience): jwks_client = PyJWKClient(jwks_url) signing_key = jwks_client.get_signing_key_from_jwt(token) secret = signing_key.key return self.verify_jwt_using_secret(token, secret, audience)