def test_non_default_headers(self, claims, key, headers): encoded = jwt.encode(claims, key, headers=headers) decoded = jwt.decode(encoded, key) assert claims == decoded all_headers = jwt.get_unverified_headers(encoded) for k, v in headers.items(): assert all_headers[k] == v
def get_claims(token: str) -> Dict[str, Union[str, int]]: # get the kid from the headers prior to verification headers: Dict[str, str] = cast(Dict[str, str], jwt.get_unverified_headers(token=token)) kid: str = headers["kid"] # search for the kid in the downloaded public keys for key in _get_keys(): if kid == key["kid"]: # construct the public key public_key = jwk.construct(key_data=key) break else: raise ValueError("Public key not found in JWK.") # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = token.rsplit(".", 1) # decode the signature decoded_signature: bytes = base64url_decode(encoded_signature.encode("utf-8")) # verify the signature if public_key.verify(msg=message.encode("utf8"), sig=decoded_signature) is False: raise RuntimeError("Signature verification failed.") print("Signature validaded.") # since we passed the verification, we can now safely use the unverified claims claims: Dict[str, Union[str, int]] = cast(Dict[str, Union[str, int]], jwt.get_unverified_claims(token)) # additionally we can verify the token expiration if time.time() > int(claims["exp"]): raise ValueError("Token expired.") print("Token not expired.") # and the Audience (use claims['client_id'] if verifying an access token) if claims["aud"] != COGNITO_USER_POOL_CLIENT_ID: raise ValueError("Token was not issued for this audience.") # now we can use the claims return claims
def verify_oidc(cls, handler): global user_cache oidc_id = handler.request.headers.get('x-amzn-oidc-identity') oidc_jwt = handler.request.headers.get('x-amzn-oidc-data') oidc_access = handler.request.headers.get('x-amzn-oidc-accesstoken') handler.log.debug("IDs: {}, {}, {}".format(oidc_id, oidc_access, oidc_jwt)) if oidc_id != user_cache.get('container_uid'): return False if not oidc_id or not oidc_jwt: return False if oidc_id != user_cache.get('user_id'): return False if oidc_jwt != user_cache.get('jwt'): return False try: header = jwt.get_unverified_headers(oidc_jwt) except JOSEError: return False kid = header.get('kid') if kid != user_cache.get('kid'): return False # TODO: TIMESTAMP CHECK return True
def get_claims(logger: logging.Logger, token: str) -> Dict[str, Union[str, int]]: # client_id = os.environ["COGNITO_APP_CLIENT_ID"] # get the kid from the headers prior to verification headers: Dict[str, str] = cast(Dict[str, str], jwt.get_unverified_headers(token=token)) kid: str = headers["kid"] # search for the kid in the downloaded public keys for key in _get_keys(logger): if kid == key["kid"]: # construct the public key public_key = jwk.construct(key_data=key) break else: raise ValueError("Public key not found in JWK.") # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = token.rsplit(".", 1) # decode the signature decoded_signature: bytes = base64url_decode(encoded_signature.encode("utf-8")) # verify the signature if public_key.verify(msg=message.encode("utf8"), sig=decoded_signature) is False: raise RuntimeError("Signature verification failed.") logger.debug("Signature validaded.") # since we passed the verification, we can now safely use the unverified claims claims = jwt.get_unverified_claims(token) # additionally we can verify the token expiration if time.time() > int(claims["exp"]): raise ValueError("Token expired.") logger.debug("Token not expired.") logger.debug("claims: %s", claims) return cast(Dict[str, Union[str, int]], claims)
def get_and_verify_claims(token): # get the kid from the headers prior to verification headers = jwt.get_unverified_headers(token) kid = headers['kid'] # search for the kid in the downloaded public keys key_index = -1 for i in range(len(keys)): if kid == keys[i]['kid']: key_index = i break if key_index == -1: raise Exception("Public key not found in jwks.json") # construct the public key public_key = jwk.construct(keys[key_index]) # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = str(token).rsplit('.', 1) # decode the signature decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) # verify the signature if not public_key.verify(message.encode("utf8"), decoded_signature): raise Exception('Signature verification failed') # since we passed the verification, we can now safely # use the unverified claims claims = jwt.get_unverified_claims(token) # additionally we can verify the token expiration if time.time() > claims['exp']: raise Exception('Token is expired') # and the Audience (use claims['client_id'] if verifying an access token) if claims['aud'] != app_client_id: raise Exception('Token was not issued for this audience') # now we can use the claims return claims
def verified_claims(token: str, app_client_id: str = os.environ.get('COGNITO_CLIENT_ID'), public_keys: dict = None) -> bool: """ verified token signature, expiry and app_id then returns claims """ headers = jwt.get_unverified_headers(token) kid = headers['kid'] public_keys = public_keys or get_cognito_public_keys() public_key = jwk.construct(public_keys[kid]) message, encoded_signature = str(token).rsplit('.', 1) decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) if not public_key.verify(message.encode("utf8"), decoded_signature): raise RuntimeError(f'Signature verification failed') claims = jwt.get_unverified_claims(token) if time.time() > claims['exp']: expiry = datetime.fromtimestamp(claims['exp']) raise RuntimeError( f"Token expired at {expiry}, it is now {datetime.now()}") if app_client_id and claims['client_id'] != app_client_id: raise RuntimeError( f"Token audience {claims['aud']} was not issued for this audience {app_client_id}" ) return claims
def __validateSignatureJWS(self, token): userPoolId = settings.AWS_CONFIG['USER_POOL_ID'] region = settings.AWS_CONFIG['REGION'] keysUrl = 'https://cognito-idp.{}.amazonaws.com/{}/.well-known/jwks.json'.format( region, userPoolId) with urllib.request.urlopen(keysUrl) as f: response = f.read() keys = json.loads(response.decode('utf-8'))['keys'] headers = jwt.get_unverified_headers(token) kid = headers['kid'] keyIndex = -1 for i in range(len(keys)): if kid == keys[i]['kid']: keyIndex = i break if keyIndex == -1: return False, 'Public key not found in jwks.json' publicKey = jwk.construct(keys[keyIndex]) payload, signature = str(token).rsplit('.', 1) decodedSignature = base64url_decode(signature.encode('utf-8')) if not publicKey.verify(payload.encode("utf8"), decodedSignature): return False, 'Signature verification failed' return True, None
def lambda_handler(event, context): print(event) token = event['request']['headers']['v-cognito-user-jwt'] headers = jwt.get_unverified_headers(token) kid = headers['kid'] key_index = -1 for i in range(len(KEYS)): if kid == KEYS[i]['kid']: key_index = i break if key_index == -1: print('Public key not found in jwks.json') return 'jwks failed validation - return Public key' public_key = jwk.construct(KEYS[key_index]) message, encoded_signature = str(token).rsplit('.', 1) decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) if not public_key.verify(message.encode('utf8'), decoded_signature): print('Signature verification failed') return 'jwks failed validation - return Signature' claims = jwt.get_unverified_claims(token) print(claims) print(claims['email']) claims['cognito_username'] = claims['cognito:username'] claims['cognito_groups'] = claims['cognito:groups'] return claims
def token_decoder(token): """ The ID token expires one hour after the user authenticates. You should not process the ID token in your client or web API after it has expired. https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html :param token: :return: """ set_cognito_data_global() token = remove_barer(token) headers = jwt.get_unverified_headers(token) kid = headers['kid'] result = {} for item in POOL_KEYS: result[item['kid']] = item public_key = jwk.construct(result.get(kid)) message, encoded_signature = str(token).rsplit('.', 1) decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) if not public_key.verify(message.encode("utf8"), decoded_signature): raise UnauthorizedError('Invalid Token') claims = jwt.get_unverified_claims(token) if time.time() > claims['exp']: raise UnauthorizedError('Token in expired!') return claims
def lambda_handler(event, context): token = event['token'] # get the kid from the headers prior to verification headers = jwt.get_unverified_headers(token) kid = headers['kid'] # search for the kid in the downloaded public keys key_index = -1 for i in range(len(keys)): if kid == keys[i]['kid']: key_index = i break if key_index == -1: print('Public key not found in jwks.json') return False # construct the public key public_key = jwk.construct(keys[key_index]) # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = str(token).rsplit('.', 1) # decode the signature decoded_signature = base64url_decode(encoded_signature) # verify the signature if public_key.verify(message, decoded_signature): print('Signature successfully verified') # since we passed the verification, now we can safely # get the unverified claims claims = jwt.get_unverified_claims(token) # do some stuff with our claims print(claims) return claims else: print('Signature verification failed') return False
def token_decoder(token): set_cognito_data_global() headers = jwt.get_unverified_headers(token) kid = headers['kid'] result = {} for item in POOL_KEYS: result[item['kid']] = item public_key = jwk.construct(result.get(kid)) message, encoded_signature = str(token).rsplit('.', 1) decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) if not public_key.verify(message.encode("utf8"), decoded_signature): app.logger.error('Signature verification failed') raise Exception app.logger.debug('Signature successfully verified') claims = jwt.get_unverified_claims(token) if time.time() > claims['exp']: app.logger.error('Token is expired') raise Exception app.logger.debug(claims) return claims
def verify_decode_jwt(token): jsonurl = urlopen(f'https://{AUTH0_DOMAIN}/.well-known/jwks.json') jwks = json.loads(jsonurl.read()) unverified_header = jwt.get_unverified_headers(token) rsa_key = {} if 'kid' not in unverified_header: raise AuthError( { 'code': 'invalid_header', 'description': 'Authorization malformed' }, 401) for key in jwks['keys']: if key['kid'] == unverified_header['kid']: rsa_key = { 'kty': key['kty'], 'kid': key['kid'], 'use': key['use'], 'n': key['n'], 'e': key['e'] } if rsa_key: try: payload = jwt.decode(token, rsa_key, algorithms=ALGORITHMS, audience=API_AUDIENCE, issuer='https://' + AUTH0_DOMAIN + '/') return payload except jwt.ExpiredSignatureError: raise AuthError( { 'code': 'token_expired', 'description': 'Token expired.' }, 401) except jwt.JWTClaimsError: raise AuthError( { 'code': 'invalid_claims', 'description': 'Incorrect claims. Please, check the audience and issuer.' }, 401) except Exception: raise AuthError( { 'code': 'invalid_header', 'description': 'Unable to parse authentication token.' }, 400) raise AuthError( { 'code': 'invalid_header', 'description': 'Unable to find the appropriate key.' }, 400)
def _get_kid(token: str) -> str: headers = jwt.get_unverified_headers(token) kid = headers.get("kid", None) if kid is None: raise Exception("Missing kid in header") return kid
def decode_cognito_token(token, cognito_clinet_id, aws_keys): result = {} try: headers = jwt.get_unverified_headers(token) except Exception as e: result = {"error": str(e)} logging.error(result) return result else: logging.info(json.dumps(headers)) id_kid = headers['kid'] logging.info(f'kid:{id_kid} found in idtoken') # search for the kid in the downloaded public keys key_index = -1 for count in range(len(aws_keys['keys'])): if aws_keys['keys'][count]['kid'] == id_kid: logging.info(f"matched idtoken kid with AWS kid index:{count}") key_index = count if key_index == -1: logging.error('Public key not found in jwks.json') result = {"error": "Public key not found in jwks.json"} return result # construct the public key public_key = jwk.construct(aws_keys['keys'][key_index]) # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = str(token).rsplit('.', 1) # decode the signature decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) # verify the signature if not public_key.verify(message.encode("utf8"), decoded_signature): logging.error('Signature verification failed') result = {"error": "Signature verification failed"} return result logging.info('Signature successfully verified') # since we passed the verification, we can now safely # use the unverified claims claims = jwt.get_unverified_claims(token) # additionally we can verify the token expiration if time.time() > claims['exp']: logging.error('Token has expired') result = {"error": "Token has expired"} return result # and the Audience (use claims['client_id'] if verifying an access token) if claims['token_use'] == 'id': if claims['aud'] != cognito_clinet_id: logging.error('Token was not issued for this audience') result = {"error": "Token was not issued for this audience"} return result if claims['token_use'] == 'access': if claims['client_id'] != cognito_clinet_id: logging.error('Token was not issued for this audience') result = {"error": "Token was not issued for this audience"} return result result['data'] = claims return result ''''''
def verify_jwt(region, user_pool_id, app_client_id, token_type, token): this_region = region this_user_pool_id = user_pool_id this_token_type = token_type this_token = token this_app_client_id = app_client_id keys_url = "https://cognito-idp.{}.amazonaws.com/{}/.well-known/jwks.json".format( this_region, this_user_pool_id ) with urllib.request.urlopen(keys_url) as f: response = f.read() keys = json.loads(response.decode("utf-8"))["keys"] headers = jwt.get_unverified_headers(this_token) kid = headers["kid"] # search for the kid in the downloaded public keys key_index = -1 for i in range(len(keys)): if kid == keys[i]["kid"]: key_index = i break if key_index == -1: log.error("Public key not found in jwks.json") return False # construct the public key public_key = jwk.construct(keys[key_index]) # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = str(this_token).rsplit(".", 1) # decode the signature decoded_signature = base64url_decode(encoded_signature.encode("utf-8")) # verify the signature if not public_key.verify(message.encode("utf8"), decoded_signature): log.error("Signature verification failed") return False log.info("Identity token signature successfully verified") # since we passed the verification, we can now safely # use the unverified claims claims = jwt.get_unverified_claims(this_token) # additionally we can verify the token expiration if time.time() > claims["exp"]: log.error("Token is expired") return False # and the Audience (use claims['client_id'] if verifying an access token) if this_token_type == "access_token": if claims["client_id"] != this_app_client_id: log.error("Token was not issued for this audience") return False elif this_token_type == "id_token": if claims["aud"] != this_app_client_id: log.error("Token was not issued for this audience") return False else: return False # now we can use the claims return claims
def search_for_key(token, keys): # get the kid from the headers prior to verification headers = jwt.get_unverified_headers(token) kid = headers["kid"] # search for the kid in the downloaded public keys for key in keys: if kid == key["kid"]: return key raise JWTError(f"Public key not found in provided keys")
def _verify(self, token): headers = jwt.get_unverified_headers(token) kid = headers['kid'] key = self._get_key(kid) public_key = jwk.construct(key) message, encoded_signature = str(token).rsplit('.', 1) decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) if not public_key.verify(message.encode("utf8"), decoded_signature): raise InvalidToken('Signature verification failed')
def decode_cognito_token(token): result = {} ''' from https://github.com/awslabs/aws-support-tools/blob/master/Cognito/decode-verify-jwt/decode-verify-jwt.py ''' try: headers = jwt.get_unverified_headers(token) except Exception as e: result = {"error": str(e)} return result else: kid = headers['kid'] # search for the kid in the downloaded public keys key_index = -1 for i in range(len(KEYS)): if kid == KEYS[i]['kid']: key_index = i break if key_index == -1: logging.error('Public key not found in jwks.json') result = {"error": "Public key not found in jwks.json"} return result # construct the public key public_key = jwk.construct(KEYS[key_index]) # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = str(token).rsplit('.', 1) # decode the signature decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) # verify the signature if not public_key.verify(message.encode("utf8"), decoded_signature): logging.error('Signature verification failed') result = {"error": "Signature verification failed"} return result logging.info('Signature successfully verified') # since we passed the verification, we can now safely # use the unverified claims claims = jwt.get_unverified_claims(token) # additionally we can verify the token expiration if time.time() > claims['exp']: logging.error('Token has expired') result = {"error": "Token has expired"} return result # and the Audience (use claims['client_id'] if verifying an access token) if claims['token_use'] == 'id': if claims['aud'] != COGNITO_CLIENT_ID: logging.error('Token was not issued for this audience') result = {"error": "Token was not issued for this audience"} return result if claims['token_use'] == 'access': if claims['client_id'] != COGNITO_CLIENT_ID: logging.error('Token was not issued for this audience') result = {"error": "Token was not issued for this audience"} return result result['data'] = claims return result
def lambda_handler(event, context): token = event['queryStringParameters']['id_token'] # get the kid from the headers prior to verification headers = jwt.get_unverified_headers(token) kid = headers['kid'] # search for the kid in the downloaded public keys key_index = -1 for i in range(len(keys)): if kid == keys[i]['kid']: key_index = i break if key_index == -1: # print('Public key not found in jwks.json') return { "statusCode":500, "body": "Public key not found" } # construct the public key public_key = jwk.construct(keys[key_index]) # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = str(token).rsplit('.', 1) # decode the signature decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) # verify the signature if not public_key.verify(message.encode("utf8"), decoded_signature): # print('Signature verification failed') return { "statusCode":500, "body": "Signature verification failed." } # since we passed the verification, we can now safely # use the unverified claims claims = jwt.get_unverified_claims(token) # additionally we can verify the token expiration if time.time() > claims['exp']: return { "statusCode":500, "body": "Token is expired." } # and the Audience (use claims['client_id'] if verifying an access token) if claims['aud'] != app_client_id: print('Token was not issued for this audience') return False # now we can use the claims #TODO SEND BACK THE JWT #TODO send back user data here? return { 'statusCode':302, 'headers': { 'location' : 'https://busy-bee.app' }, 'body': json.dumps(claims) }
def sso_authorization(code): authorization = 'Basic ' + base64.b64encode( (config.Config.COGNITO_APP_ID + ':' + config.Config.COGNITO_APP_SECRET).encode()).decode() headers = { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': authorization } data = { 'grant_type': 'authorization_code', 'client_id': config.Config.COGNITO_APP_ID, 'code': code, 'redirect_uri': config.Config.COGNITO_CALLBACK_URL } oauth_token = requests.post(config.Config.COGNITO_OAUTH_TOKEN_ENDPOINT, data=data, headers=headers).json() id_token = oauth_token['id_token'] access_token = oauth_token['access_token'] headers = jwt.get_unverified_headers(id_token) keys = requests.get( config.Config.COGNITO_JWS_KEYS_ENDPOINT).json().get('keys') key = list(filter(lambda k: k['kid'] == headers['kid'], keys)).pop() claims = jwt.decode(id_token, key, access_token=access_token, algorithms=[key['alg']], audience=config.Config.COGNITO_APP_ID) if claims: try: user = claims['email'].split('@')[0] except Exception as err: return { 'success': False, 'message': 'Error reading SSO claims. ' + str(claims) + ' Err: ' + str(err) } # Simply check if user exist check_user = get(config.Config.FLASK_ENDPOINT + "/api/ldap/user", headers={"X-SOCA-TOKEN": config.Config.API_ROOT_KEY}, params={"user": user}, verify=False) # nosec if check_user.status_code == 200: session['user'] = user return {'success': True, 'message': ''} else: return {'success': False, 'message': 'user_not_found'} else: return {'success': False, 'message': 'SSO error. ' + str(claims)}
def validate_token(config, token): region = 'us-east-1' user_record = {} keys_url = 'https://cognito-idp.{}.amazonaws.com/{}/.well-known/jwks.json'.format( region, config['cognito_pool']) response = urlopen(keys_url) keys = json.loads(response.read())['keys'] headers = jwt.get_unverified_headers(token) kid = headers['kid'] # search for the kid in the downloaded public keys key_index = -1 for i in range(len(keys)): if kid == keys[i]['kid']: key_index = i break if key_index == -1: log_error('Public key not found in jwks.json') return False # construct the public key public_key = jwk.construct(keys[key_index]) # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = str(token).rsplit('.', 1) # decode the signature decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) # verify the signature if not public_key.verify(message.encode("utf8"), decoded_signature): log_error('Signature verification failed') return 'False' # since we passed the verification, we can now safely # use the unverified claims claims = jwt.get_unverified_claims(token) log_error('Token claims = ' + json.dumps(claims)) # additionally we can verify the token expiration if time.time() > claims['exp']: log_error('Token is expired') return 'False' if claims['aud'] != config['cognito_client_id']: log_error('Token claims not valid for this application') return 'False' user_record['username'] = claims['cognito:username'] user_record['token'] = token return user_record
def is_token_valid(token: str): # print("in is token valid") # print(token) global CERTS # get the kid from the headers prior to verification headers = jwt.get_unverified_headers(token) kid = headers['kid'] # use that kid to get the public key from keycloak key_data = get_public_key_data(kid) # construct the public key public_key = jwk.construct(key_data) # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = str(token).rsplit('.', 1) # decode the signature decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) # verify the signature if not public_key.verify(message.encode("utf8"), decoded_signature): raise HTTPException( status_code=400, detail="Invalid token, {}".format("failed signature"), headers={"WWW-Authenticate": "Bearer"}, ) # since we passed the verification, we can now safely # use the unverified claims claims = jwt.get_unverified_claims(token) # print(claims) # additionally we can verify the token expiration if time.time() > claims['exp']: # time() returns epoch (UTC) print('Token has expired') if claims.get("resource_access"): if "Epiviz" in claims.get("resource_access"): return User(username=claims.get("preferred_username"), email=claims.get("email"), full_name=claims.get("name"), roles=claims.get("resource_access")["Epiviz"]["roles"]) elif "Epiviz-backend" in claims.get("resource_access"): return User( username=claims.get("preferred_username"), email=claims.get("email"), full_name=claims.get("name"), roles=claims.get("resource_access")["Epiviz-backend"]["roles"]) return User(username=claims.get("preferred_username"), email=claims.get("email"), full_name=claims.get("name"))
def _verify_id_token(self): try: keys_url = 'https://cognito-idp.{}.amazonaws.com/{}/.well-known/jwks.json'.format( self.region, self.user_pool_id) response = urllib.urlopen(keys_url) keys = json.loads(response.read())['keys'] # get the kid from the headers prior to verification headers = josejwt.get_unverified_headers(self.id_token) kid = headers['kid'] # search for the kid in the downloaded public keys key_index = -1 for i in range(len(keys)): if kid == keys[i]['kid']: key_index = i break if key_index == -1: print('Public key not found in jwks.json') return False # construct the public key public_key = jwk.construct(keys[key_index]) # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = str(self.id_token).rsplit('.', 1) # decode the signature decoded_signature = base64url_decode( encoded_signature.encode('utf-8')) # verify the signature if not public_key.verify(message.encode("utf8"), decoded_signature): print('Signature verification failed') return False print('Signature successfully verified') # since we passed the verification, we can now safely # use the unverified claims claims = josejwt.get_unverified_claims(self.id_token) # additionally we can verify the token expiration if time.time() > claims['exp']: print('Token is expired') return False # and the Audience (use claims['client_id'] if verifying an access token) if claims['aud'] != self.client_id: print('Token was not issued for this audience') return False # now we can use the claims # print(claims) return True except Exception as e: print("Error verifying token: %s" % e.message) return False
def decode_verify_jwt_token(self, jwt_token): # copied from https://github.com/awslabs/aws-support-tools/blob/master/Cognito/decode-verify-jwt/decode-verify-jwt.py token = jwt_token # get the kid from the headers prior to verification headers = jwt.get_unverified_headers(token) kid = headers['kid'] # search for the kid in the downloaded public keys key_index = -1 for i in range(len(self.keys)): if kid == self.keys[i]['kid']: key_index = i break if key_index == -1: logging.warning('Public key not found in jwks.json') return False # construct the public key public_key = jwk.construct(self.keys[key_index]) # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = str(token).rsplit('.', 1) # decode the signature decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) # verify the signature if not public_key.verify(message.encode("utf8"), decoded_signature): logging.warning('Signature verification failed') return False # print('Signature successfully verified') # since we passed the verification, we can now safely # use the unverified claims claims = jwt.get_unverified_claims(token) # additionally we can verify the token expiration if time.time() > claims['exp']: logging.warning('Token is expired') return False # and the Audience (use claims['client_id'] if verifying an access token) if claims['aud'] != self.CLIENT_ID: logging.warning('Token was not issued for this audience') return False # now we can use the claims # print(claims) return claims
def lambda_handler(event, context): try: # TODO: write code... token = event['token'] # get the kid from the headers prior to verification headers = jwt.get_unverified_headers(token) kid = headers['kid'] # search for the kid in the downloaded public keys key_index = -1 for i in range(len(keys)): if kid == keys[i]['kid']: key_index = i break if key_index == -1: print('Public key not found in jwks.json') return False # construct the public key public_key = jwk.construct(keys[key_index]) # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = str(token).rsplit('.', 1) # decode the signature decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) # verify the signature if not public_key.verify(message.encode("utf8"), decoded_signature): print('Signature verification failed') return False claims = jwt.get_unverified_claims(token) # additionally we can verify the token expiration if time.time() > claims['exp']: print('Token is expired') return False # and the Audience (use claims['client_id'] if verifying an access token) if claims['aud'] != app_client_id: print('Token was not issued for this audience') return False # now we can use the claims print(claims) return claims except Exception: return False
def verifyToken(cls, event, context): region = 'us-east-1' userpool_id = 'us-east-1_g7vZomsGY' app_client_id = '2pubneliqokqtnlpqdg6jl89sv' keys_url = 'https://cognito-idp.{}.amazonaws.com/{}/.well-known/jwks.json'.format( region, userpool_id) # instead of re-downloading the public keys every time # we download them only on cold start # https://aws.amazon.com/blogs/compute/container-reuse-in-lambda/ response = urllib.urlopen(keys_url) keys = json.loads(response.read())['keys'] token = event['token'] # get the kid from the headers prior to verification headers = jwt.get_unverified_headers(token) kid = headers['kid'] # search for the kid in the downloaded public keys key_index = -1 for i in range(len(keys)): if kid == keys[i]['kid']: key_index = i break if key_index == -1: print('Public key not found in jwks.json') return False # construct the public key public_key = jwk.construct(keys[key_index]) # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = str(token).rsplit('.', 1) # decode the signature decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) # verify the signature if not public_key.verify(message.encode("utf8"), decoded_signature): print('Signature verification failed') return False print('Signature successfully verified') # since we passed the verification, we can now safely # use the unverified claims claims = jwt.get_unverified_claims(token) # additionally we can verify the token expiration if time.time() > claims['exp']: print('Token is expired') return False # and the Audience (use claims['client_id'] if verifying an access token) if claims['aud'] != app_client_id: print('Token was not issued for this audience') return False # now we can use the claims print(claims) return claims
def decode_verify_jwt(token): response = {"status": {"code": 200, "message": ""}, "data": {}} headers = jwt.get_unverified_headers(token) kid = headers['kid'] # search for the kid in the downloaded public keys key_index = -1 for i in range(len(keys)): if kid == keys[i]['kid']: key_index = i break if key_index == -1: logger.error('Public key not found in jwks.json') response["status"]["code"] = 400 response["status"]["message"] = "Public key not found in jwks.json" return response # construct the public key public_key = jwk.construct(keys[key_index]) # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = str(token).rsplit('.', 1) # decode the signature decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) # verify the signature if not public_key.verify(message.encode("utf8"), decoded_signature): logger.error('Signature verification failed') response["status"]["code"] = 400 response["status"]["message"] = "Signature verification failed" return response logger.info('Signature successfully verified') # since we passed the verification, we can now safely # use the unverified claims claims = jwt.get_unverified_claims(token) # additionally we can verify the token expiration if time.time() > claims['exp']: logger.debug('Token is expired') response["status"]["code"] = 400 response["status"]["message"] = "Token is expired" return response # and the Audience (use claims['client_id'] if verifying an access token) if claims['client_id'] != app_client_id: logger.error('Token was not issued for this audience') response["status"]["code"] = 400 response["status"][ "message"] = "Token was not issued for this audience" return response # now we can use the claims response["data"] = claims return response
def lambda_handler(event, context): print(event) token = event['headers']['x-amz-security-token'] # get the kid from the headers pterior to verification headers = jwt.get_unverified_headers(token) kid = headers['kid'] # search for the kid in the downloaded public keys key_index = -1 for i in range(len(keys)): if kid == keys[i]['kid']: key_index = i break if key_index == -1: print('Public key not found in jwks.json') return False # construct the public key public_key = jwk.construct(keys[key_index]) # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = str(token).rsplit('.', 1) # decode the signature decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) # verify the signature if not public_key.verify(message.encode("utf8"), decoded_signature): print('Signature verification failed') return False print('Signature successfully verified') # since we passed the verification, we can now safely # use the unverified claims claims = jwt.get_unverified_claims(token) # additionally we can verify the token expiration if time.time() > claims['exp']: print('Token is expired') return False # and the Audience (use claims['client_id'] if verifying an access token) if claims['aud'] != app_client_id: print('Token was not issued for this audience') return False # now we can use the claims print(claims) return { "statusCode": 200, "body": json.dumps(claims), "headers": { 'Access-Control-Allow-Headers': 'Content-Type', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'OPTIONS,POST,GET' } }
def validate_token(token, region): global keys, is_cold_start, user_pool_id, app_client_id if is_cold_start: keys_url = f'https://cognito-idp.{region}.amazonaws.com/{user_pool_id}/.well-known/jwks.json' with urllib.request.urlopen(keys_url) as f: response = f.read() keys = json.loads(response.decode('utf-8'))['keys'] is_cold_start = False # get the kid from the headers prior to verification headers = jwt.get_unverified_headers(token) kid = headers['kid'] # search for the kid in the downloaded public keys key_index = -1 for i in range(len(keys)): if kid == keys[i]['kid']: key_index = i break if key_index == -1: print('Public key not found in jwks.json') return False # construct the public key public_key = jwk.construct(keys[key_index]) # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = str(token).rsplit('.', 1) # decode the signature decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) # verify the signature if not public_key.verify(message.encode("utf8"), decoded_signature): print('Signature verification failed') return False print('Signature successfully verified') # since we passed the verification, we can now safely # use the unverified claims claims = jwt.get_unverified_claims(token) # additionally we can verify the token expiration if time.time() > claims['exp']: print('Token is expired') return False # and the Audience (use claims['client_id'] if verifying an access token) if claims['aud'] != app_client_id: print('Token was not issued for this audience') return False decoded_jwt = jwt.decode(token, key=keys[key_index], audience=app_client_id) return decoded_jwt
def get_verified_token(event): token = event["headers"].get("Authorization") or event["queryStringParameters"].get( "token" ) headers = jwt.get_unverified_headers(token) kid = headers["kid"] key_index = -1 for i in range(len(JWKS_KEYS)): if kid == JWKS_KEYS[i]["kid"]: key_index = i break if key_index == -1: return None return jwt.decode(token, JWKS_KEYS[key_index], audience=COGNITO_APP_CLIENT_ID)
def fromJWT(self, token, publicKey, needOrgID, algorithm="HS256", really_dont_verify_tokens=False): """ Decode a JWT into a credential. You must know the orgID for which the cred should have been issued, because we need to verify that it matches. Returns a DataWireResult with a cred member on success. """ cred = None claims = None errorMessage = None try: if not publicKey: if not really_dont_verify_tokens: errorMessage = "public key is required to decode JWT" else: header = jwt.get_unverified_headers(token) if ("typ" not in header) or (header["typ"] != "JWT"): errorMessage = "malformed token (not a JWT)" elif ("alg" not in header) or (header["alg"] != "HS256"): errorMessage = "malformed token (not HS256)" else: claims = jwt.get_unverified_claims(token) else: claims = jwt.decode( token, publicKey, algorithms=algorithm, audience=needOrgID, issuer="cloud-hub.datawire.io" ) except JWSError as error: errorMessage = error.message if claims: rc = DataWireCredential.fromClaims(claims, needOrgID) if rc: cred = rc.cred else: errorMessage = rc.error return DataWireResult.fromErrorAndResults(error=errorMessage, cred=cred)
def test_no_alg_default_headers(self, claims, key, headers): token = jwt.encode(claims, key, algorithm='HS384') b64header, b64payload, b64signature = token.split('.') bad_token = b64header + '.' + b64payload with pytest.raises(JWTError): jwt.get_unverified_headers(bad_token)