Example #1
0
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
Example #2
0
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
Example #3
0
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
Example #4
0
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
Example #5
0
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
Example #6
0
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
Example #7
0
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
Example #8
0
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")