base64.b64encode(text.encode()).decode() turns a Python string into a Base64 string. .encode() gives the text’s UTF-8 bytes, b64encode encodes them, and .decode() turns the result back into a str.
import base64
text = "Grüße"
base64.b64encode(text.encode()).decode()
# 'R3LDvMOfZQ=='
The tool below gives the same R3LDvMOfZQ==. Grüße is 5 characters but 7 bytes, because ü and ß take two bytes each in UTF-8.
Bytes in, bytes out
b64encode works on bytes, not text. Pass it a str and it refuses:
base64.b64encode("Grüße")
# TypeError: a bytes-like object is required, not 'str'
It returns bytes too, and leaving off the final .decode() is the other half of the mistake. An f-string writes the bytes with their b'...' around them, and json.dumps won’t take them at all:
import json
encoded = base64.b64encode("Grüße".encode())
f"Authorization: Basic {encoded}"
# "Authorization: Basic b'R3LDvMOfZQ=='"
json.dumps({"data": encoded})
# TypeError: Object of type bytes is not JSON serializable
str.encode() always means UTF-8 unless you name another codec, and the codec changes the result. The Latin-1 bytes of the same word encode to something else, which a UTF-8 decoder can’t read back:
base64.b64encode("Grüße".encode("latin-1")).decode()
# 'R3L832U='
URL-safe output
base64.urlsafe_b64encode uses - and _ in place of + and /, but it keeps the = padding. JWTs and most URL tokens leave it off, so strip it:
base64.urlsafe_b64encode(text.encode()).rstrip(b"=").decode()
# 'R3LDvMOfZQ'
Line breaks
base64.encodebytes is the MIME variant (RFC 2045). It breaks the output every 76 characters and adds a trailing newline, even to a short input. b64encode never adds line breaks:
base64.encodebytes(b"x" * 60)
# b'eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\neHh4\n'
Files
Read the file in binary mode, and don’t decode it:
with open("greeting.txt", "rb") as f:
encoded = base64.b64encode(f.read()).decode()
# 'R3LDvMOfZQo=' for a file holding "Grüße" and a newline
It ends in ZQo= rather than ZQ== because of the newline most editors put at the end of a file: 8 bytes, not 7.