Base64 encode in Python

base64.b64encode(text.encode()).decode()

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.

Try it in the Base64 Encoder & Decoder

Nothing leaves your browser: the conversion happens here, in the page.

Base64
R3LDvMOfZQ==

7 bytes of UTF-8, written as 12 Base64 characters.

Runs in your browser. Nothing you enter is sent anywhere.