"""Implementation of `PKCE <https://datatracker.ietf.org/doc/html/rfc7636>`_ code challenge and verifier generation.Original code from `@RomeoDespres <https://github.com/RomeoDespres/>`_ in their `pkce repository <https://github.com/RomeoDespres/pkce/blob/b74b1864dc8a2018ca86566a5cfa2fd9fe751c4d/pkce/__init__.py>`_:Examples-------->>> from simple_openid_connect import pkce>>> code_verifier, code_challenge = pkce.generate_pkce_pair()>>> from simple_openid_connect import pkce>>> code_verifier = pkce.generate_code_verifier(length=128)>>> code_challenge = pkce.get_code_challenge(code_verifier)"""importbase64importhashlibimportsecretsfromtypingimportTuple
[docs]defgenerate_code_verifier(length:int=128)->str:""" Return a random PKCE-compliant code verifier. :param length: Code verifier length. Must be betwen 43 and 128. :raises ValueError: When `length` is not between 43 and 128. :returns: A url-safe string ready to be used as a code verifier. """ifnot43<=length<=128:msg="Parameter `length` must verify `43 <= length <= 128`."raiseValueError(msg)code_verifier=secrets.token_urlsafe(96)[:length]returncode_verifier
[docs]defgenerate_pkce_pair(code_verifier_length:int=128)->Tuple[str,str]:""" Return random PKCE-compliant code verifier and its corresponding code challenge. :param code_verifier_length: Length of the generated code verifier. Must be between 43 and 128. :raises ValueError: When `code_verifier_length` is not between 43 and 128. :returns code_verifier, code_challenge: A tuple containing the code verifier along with its corresponding challenge. """ifnot43<=code_verifier_length<=128:msg="Parameter `code_verifier_length` must verify "msg+="`43 <= code_verifier_length <= 128`."raiseValueError(msg)code_verifier=generate_code_verifier(code_verifier_length)code_challenge=get_code_challenge(code_verifier)returncode_verifier,code_challenge
[docs]defget_code_challenge(code_verifier:str)->str:""" Generate the corresponding code challenge for a given verifier. :param code_verifier: The code verifier from which a challenge should be derived. :raises ValueError: When `code_verifier` is not bettween 43 and 128 long. :returns: The url-safe challenge string that corresponds to the given verifier. """ifnot43<=len(code_verifier)<=128:msg="Parameter `code_verifier` must verify "msg+="`43 <= len(code_verifier) <= 128`."raiseValueError(msg)hashed=hashlib.sha256(code_verifier.encode("ascii")).digest()encoded=base64.urlsafe_b64encode(hashed)code_challenge=encoded.decode("ascii")[:-1]returncode_challenge