@@ -530,6 +530,8 @@ def parse_authorization_basic(header: str) -> tuple[str, str]:
530530
531531 Return a ``(username, password)`` tuple.
532532
533+ Non-UTF-8 data is represented with surrogate code points.
534+
533535 Args:
534536 header: Value of the ``Authorization`` header.
535537
@@ -555,12 +557,13 @@ def parse_authorization_basic(header: str) -> tuple[str, str]:
555557 parse_end (header , pos , "Authorization" )
556558
557559 try :
558- user_pass = base64 .b64decode (basic_credentials .encode ()). decode ( )
560+ user_pass_bytes = base64 .b64decode (basic_credentials .encode ())
559561 except binascii .Error :
560562 raise InvalidHeaderValue (
561563 "Authorization" ,
562564 "expected base64-encoded credentials" ,
563565 ) from None
566+ user_pass = user_pass_bytes .decode (errors = "surrogateescape" )
564567 try :
565568 username , password = user_pass .split (":" , 1 )
566569 except ValueError :
@@ -578,9 +581,12 @@ def build_authorization_basic(username: str, password: str) -> str:
578581
579582 This is the reverse of :func:`parse_authorization_basic`.
580583
584+ Non-UTF-8 data can be represented with surrogate code points.
585+
581586 """
582587 # https://datatracker.ietf.org/doc/html/rfc7617#section-2
583588 assert ":" not in username
584589 user_pass = f"{ username } :{ password } "
585- basic_credentials = base64 .b64encode (user_pass .encode ()).decode ()
590+ user_pass_bytes = user_pass .encode (errors = "surrogateescape" )
591+ basic_credentials = base64 .b64encode (user_pass_bytes ).decode ()
586592 return "Basic " + basic_credentials
0 commit comments