Base64 decode in Python

base64.b64decode(encoded).decode()

base64.b64decode(encoded).decode() turns a Base64 string back into text. b64decode returns bytes, and .decode() reads them as UTF-8.

import base64

encoded = "R3LDvMOfZQ=="
base64.b64decode(encoded)
# b'Gr\xc3\xbc\xc3\x9fe'
base64.b64decode(encoded).decode()
# 'Grüße'

The tool below decodes the same string to Grüße, 7 bytes. The outputs here are from Python 3.14.

Incorrect padding

b64decode needs the = padding that base64url, JWTs and many APIs leave off. The tool reads R3LDvMOfZQ without it; Python doesn’t:

base64.b64decode("R3LDvMOfZQ")
# binascii.Error: Incorrect padding

Add back as many = as it takes to reach a multiple of 4. -len(s) % 4 is that number, from 0 to 3:

s = "R3LDvMOfZQ"
base64.b64decode(s + "=" * (-len(s) % 4)).decode()
# 'Grüße'

URL-safe input

Strings with - and _ need base64.urlsafe_b64decode. The standard decoder doesn’t fail on them: it drops them, along with any other character outside its alphabet, and decodes what’s left.

base64.b64decode("PDw_Pz8-Pg==")
# b'<<\x0f\xcf\xc3\xe0'
base64.urlsafe_b64decode("PDw_Pz8-Pg==")
# b'<<???>>'

The same leniency lets junk through. Pass validate=True to get an error instead:

base64.b64decode("R3LD!!vMOfZQ==")
# b'Gr\xc3\xbc\xc3\x9fe'
base64.b64decode("R3LD!!vMOfZQ==", validate=True)
# binascii.Error: Only base64 data is allowed

Spaces and line breaks count as junk too. With validate=True, even the newline at the end of a line read from a file fails, with binascii.Error: Excess data after padding, so call .strip() first.

Bytes that aren’t UTF-8

Base64 can hold any bytes, and .decode() fails on bytes that aren’t UTF-8, such as text that was encoded as Latin-1:

base64.b64decode("R3L832U=").decode()
# UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfc in position 2: invalid start byte
base64.b64decode("R3L832U=").decode("latin-1")
# 'Grüße'

Use the codec the sender used. If the bytes are an image or a file, don’t decode them at all: write them out with open(path, "wb"). The tool shows such bytes as hex, 47 72 fc df 65 for this one.

Try it in the Base64 Encoder & Decoder

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

Text
Grüße

7 bytes of Base64, and they spell UTF-8 text. A decode reads either alphabet, with or without its padding, so the choice above only matters when encoding.

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