def decode_jwt(encoded_token, secret, algorithm, csrf, identity_claim): """ Decodes an encoded JWT :param encoded_token: The encoded JWT string to decode :param secret: Secret key used to encode the JWT :param algorithm: Algorithm used to encode the JWT :param csrf: If this token is expected to have a CSRF double submit value present (boolean) :param identity_claim: expected claim that is used to identify the subject :return: Dictionary containing contents of the JWT """ # This call verifies the ext, iat, and nbf claims data = jwt.decode(encoded_token, secret, algorithms=[algorithm]) # Make sure that any custom claims we expect in the token are present if 'jti' not in data: raise JWTDecodeError("Missing claim: jti") if identity_claim not in data: raise JWTDecodeError("Missing claim: {}".format(identity_claim)) if 'type' not in data or data['type'] not in ('refresh', 'access'): raise JWTDecodeError("Missing or invalid claim: type") if data['type'] == 'access': if 'fresh' not in data: raise JWTDecodeError("Missing claim: fresh") if 'user_claims' not in data: data['user_claims'] = {} if csrf: if 'csrf' not in data: raise JWTDecodeError("Missing claim: csrf") return data
def _decode_jwt_from_cookies(type): if type == 'access': cookie_key = get_access_cookie_name() else: cookie_key = get_refresh_cookie_name() token = request.cookies.get(cookie_key) if not token: raise NoAuthorizationError('Missing cookie "{}"'.format(cookie_key)) secret = _get_secret_key() algorithm = get_algorithm() token = _decode_jwt(token, secret, algorithm) if get_cookie_csrf_protect( ) and request.method in get_csrf_request_methods(): csrf_header_key = get_csrf_header_name() csrf_token_from_header = request.headers.get(csrf_header_key, None) csrf_token_from_cookie = token.get('csrf', None) # Verify the csrf tokens are present and matching if csrf_token_from_cookie is None: raise JWTDecodeError("Missing claim: 'csrf'") if not isinstance(csrf_token_from_cookie, six.string_types): raise JWTDecodeError("Invalid claim: 'csrf' (must be a string)") if csrf_token_from_header is None: raise CSRFError("Missing CSRF token in headers") if not safe_str_cmp(csrf_token_from_header, csrf_token_from_cookie): raise CSRFError("CSRF double submit tokens do not match") return token
def _decode_jwt(token, secret, algorithm): """ Decodes an encoded JWT :param token: The encoded JWT string to decode :param secret: Secret key used to encode the JWT :param algorithm: Algorithm used to encode the JWT :return: Dictionary containing contents of the JWT """ # ext, iat, and nbf are all verified by pyjwt. We just need to make sure # that the custom claims we put in the token are present data = jwt.decode(token, secret, algorithm=algorithm) if 'jti' not in data or not isinstance(data['jti'], six.string_types): raise JWTDecodeError("Missing or invalid claim: jti") if 'identity' not in data: raise JWTDecodeError("Missing claim: identity") if 'type' not in data or data['type'] not in ('refresh', 'access'): raise JWTDecodeError("Missing or invalid claim: type") if data['type'] == 'access': if 'fresh' not in data or not isinstance(data['fresh'], bool): raise JWTDecodeError("Missing or invalid claim: fresh") if 'user_claims' not in data or not isinstance(data['user_claims'], dict): raise JWTDecodeError("Missing or invalid claim: user_claims") return data
def decode_jwt(encoded_token, secret, algorithm, identity_claim_key, user_claims_key, csrf_value=None): """ Decodes an encoded JWT :param encoded_token: The encoded JWT string to decode :param secret: Secret key used to encode the JWT :param algorithm: Algorithm used to encode the JWT :param identity_claim_key: expected key that contains the identity :param user_claims_key: expected key that contains the user claims :param csrf_value: Expected double submit csrf value :return: Dictionary containing contents of the JWT """ # This call verifies the ext, iat, and nbf claims data = jwt.decode(encoded_token, secret, algorithms=[algorithm]) # Make sure that any custom claims we expect in the token are present if 'jti' not in data: raise JWTDecodeError("Missing claim: jti") if identity_claim_key not in data: raise JWTDecodeError("Missing claim: {}".format(identity_claim_key)) if 'type' not in data or data['type'] not in ('refresh', 'access'): raise JWTDecodeError("Missing or invalid claim: type") if data['type'] == 'access': if 'fresh' not in data: raise JWTDecodeError("Missing claim: fresh") if user_claims_key not in data: data[user_claims_key] = {} if csrf_value: if 'csrf' not in data: raise JWTDecodeError("Missing claim: csrf") if not safe_str_cmp(data['csrf'], csrf_value): raise CSRFError("CSRF double submit tokens do not match") return data
def decode_jwt( encoded_token, secret, algorithms, identity_claim_key, user_claims_key, csrf_value=None, audience=None, leeway=0, allow_expired=False, ): """ Decodes an encoded JWT :param encoded_token: The encoded JWT string to decode :param secret: Secret key used to encode the JWT :param algorithms: Algorithms allowed to decode the token :param identity_claim_key: expected key that contains the identity :param user_claims_key: expected key that contains the user claims :param csrf_value: Expected double submit csrf value :param audience: expected audience in the JWT :param leeway: optional leeway to add some margin around expiration times :param allow_expired: Options to ignore exp claim validation in token :return: Dictionary containing contents of the JWT """ options = {} if allow_expired: options["verify_exp"] = False # This call verifies the ext, iat, nbf, and aud claims data = jwt.decode( encoded_token, secret, algorithms=algorithms, audience=audience, leeway=leeway, options=options, ) # Make sure that any custom claims we expect in the token are present if "jti" not in data: data["jti"] = None if identity_claim_key not in data: raise JWTDecodeError("Missing claim: {}".format(identity_claim_key)) if "type" not in data: data["type"] = "access" if data["type"] not in ("refresh", "access"): raise JWTDecodeError("Missing or invalid claim: type") if data["type"] == "access": if "fresh" not in data: data["fresh"] = False if user_claims_key not in data: data[user_claims_key] = {} if csrf_value: if "csrf" not in data: raise JWTDecodeError("Missing claim: csrf") if not safe_str_cmp(data["csrf"], csrf_value): raise CSRFError("CSRF double submit tokens do not match") return data
def _decode_jwt( algorithms, allow_expired, audience, csrf_value, encoded_token, identity_claim_key, issuer, leeway, secret, verify_aud, ): options = {"verify_aud": verify_aud} if allow_expired: options["verify_exp"] = False # This call verifies the ext, iat, and nbf claims # This optionally verifies the exp and aud claims if enabled decoded_token = jwt.decode( encoded_token, secret, algorithms=algorithms, audience=audience, issuer=issuer, leeway=leeway, options=options, ) # Make sure that any custom claims we expect in the token are present if identity_claim_key not in decoded_token: raise JWTDecodeError("Missing claim: {}".format(identity_claim_key)) if "type" not in decoded_token: decoded_token["type"] = "access" if decoded_token["type"] not in ("access", "refresh"): raise JWTDecodeError("Invalid token type: {}".format( decoded_token["type"])) if "fresh" not in decoded_token: decoded_token["fresh"] = False if "jti" not in decoded_token: decoded_token["jti"] = None if csrf_value: if "csrf" not in decoded_token: raise JWTDecodeError("Missing claim: csrf") if not safe_str_cmp(decoded_token["csrf"], csrf_value): raise CSRFError("CSRF double submit tokens do not match") return decoded_token
def _decode_jwt( algorithms: Iterable, allow_expired: bool, audience: Union[str, Iterable[str]], csrf_value: str, encoded_token: str, identity_claim_key: str, issuer: str, leeway: int, secret: str, verify_aud: bool, ) -> dict: options = {"verify_aud": verify_aud} if allow_expired: options["verify_exp"] = False # This call verifies the ext, iat, and nbf claims # This optionally verifies the exp and aud claims if enabled decoded_token = jwt.decode( encoded_token, secret, algorithms=algorithms, audience=audience, issuer=issuer, leeway=leeway, options=options, ) # Make sure that any custom claims we expect in the token are present if identity_claim_key not in decoded_token: raise JWTDecodeError("Missing claim: {}".format(identity_claim_key)) if "type" not in decoded_token: decoded_token["type"] = "access" if "fresh" not in decoded_token: decoded_token["fresh"] = False if "jti" not in decoded_token: decoded_token["jti"] = None if csrf_value: if "csrf" not in decoded_token: raise JWTDecodeError("Missing claim: csrf") if not compare_digest(decoded_token["csrf"], csrf_value): raise CSRFError("CSRF double submit tokens do not match") return decoded_token
def decode_jwt(encoded_token, secret, algorithm, identity_claim_key, user_claims_key, csrf_value=None, audience=None, leeway=0, allow_expired=False, verify_audience=False): """ Decodes an encoded JWT :param encoded_token: The encoded JWT string to decode :param secret: Secret key used to encode the JWT :param algorithm: Algorithm used to encode the JWT :param identity_claim_key: expected key that contains the identity :param user_claims_key: expected key that contains the user claims :param csrf_value: Expected double submit csrf value :param audience: expected audience in the JWT :param leeway: optional leeway to add some margin around expiration times :param allow_expired: Options to ignore exp claim validation in token :param verify_audience: Options to ignore aud claim validation in token :return: Dictionary containing contents of the JWT """ options = {} if allow_expired: options['verify_exp'] = False options['verify_aud'] = verify_audience # This call verifies the ext, iat, nbf, and aud claims data = jwt.decode(encoded_token, secret, algorithms=[algorithm], audience=audience, leeway=leeway, options=options) # Make sure that any custom claims we expect in the token are present if 'jti' not in data: data['jti'] = None if identity_claim_key not in data: raise JWTDecodeError("Missing claim: {}".format(identity_claim_key)) if 'type' not in data: data['type'] = 'access' if data['type'] not in ('refresh', 'access'): raise JWTDecodeError("Missing or invalid claim: type") if data['type'] == 'access': if 'fresh' not in data: data['fresh'] = False if user_claims_key not in data: data[user_claims_key] = {} if csrf_value: if 'csrf' not in data: raise JWTDecodeError("Missing claim: csrf") if not safe_str_cmp(data['csrf'], csrf_value): raise CSRFError("CSRF double submit tokens do not match") return data
def get_user_from_reset_token(reset_token): """Returns a user from a reset_token""" _check_flask_jwt_extended() decoded_token = _decode_reset_token(reset_token) user = User.find(decoded_token[config.identity_claim_key]) if not decoded_token["jti"] == password_verification(user.password): raise JWTDecodeError("Reset link can only be used once") return user
def _decode_reset_token(reset_token): """Decodes a jwt reset token""" _check_flask_jwt_extended() try: data = jwt.decode( reset_token, config.decode_key, algorithms=[config.algorithm], audience=config.audience, leeway=config.leeway, ) if config.identity_claim_key not in data: raise JWTDecodeError("Missing claim: {}".format(config.identity_claim_key)) if data.get("type") != "password_reset": raise JWTDecodeError("Token is not a reset token") return data except jwt.exceptions.DecodeError: raise JWTDecodeError("Not a valid jwt token")