Encode Binary Data with Python base64
Convert text to bytes before Base64 encoding and validate decoded input before using it.
Example check: Worked and guided code samples are checked against CPython 3.13. Practice uses Pyodide 0.29.5 (Python 3.13) in your browser. How we check lessons
Video lesson: Encode Binary Data with Python base64
The preview is stored on this site. YouTube loads only when you press Play. Watch on YouTube
Jump to a chapter
Read the video transcript
Select a timestamp to watch that moment on YouTube.
- 00:00
Base64 looks like text. What happens if b64encode receives the Python string 'Python'? Watch the first run and its TypeError. Then we will make the clean token UHl0aG9u. The broken source imports base64 and passes a string directly into b64encode. The terminal raises TypeError because the function requires a bytes-like object. Python cannot infer which character encoding the caller intended. That matters even with a simple word, and it matters more for characters such as the accented e in café. The first repair is to call encode with UTF-8, producing bytes.
- 00:41
There is a second trap after that: str of an encoded bytes object gives a debugging representation beginning with the letter b and containing quotation marks. It does not give a clean token that another system should receive. We need to decode the Base64 output as ASCII. Watch for those two conversions in opposite directions: UTF-8 changes text into bytes before Base64, while ASCII changes the encoded bytes into transport text after Base64. The diagnosis run makes the intermediate type visible. raw is bytes, and the terminal shows b'Python'. Those six bytes are valid input to b64encode, which returns another bytes
- 01:25
object whose contents spell UHl0aG9u. The leading b in the Python representation identifies the type; it is not part of the Base64 alphabet or the value we want to send. Why eight token characters? Python is six UTF-8 bytes. Base64 processes three input bytes into four printable characters, so six bytes fill two groups without padding. We also compare two encodings of the byte values 251 and 255. Standard Base64 prints plus slash eight equals. URL-safe Base64 prints hyphen underscore eight equals, or -_8=.
- 02:09
That two-byte sample needs one equals sign for padding. The URL-safe variant changes two alphabet characters that are awkward in a URL component. It may still include equals-sign padding, and neither alphabet makes the data secret. The receiver must know which variant to decode and then validate what the decoded bytes are supposed to mean. Base64 also grows the data; it is representation, not compression. The corrected encode_label function begins with text.encode using UTF-8. It hands the resulting bytes to base64.b64encode, then calls decode with ASCII on the result.
- 02:50
For the public sample word Python, the terminal prints UHl0aG9u without a leading b or surrounding quotes. Each conversion has a separate purpose. UTF-8 defines how characters become source bytes; Base64 represents those bytes using a restricted alphabet; ASCII turns the encoded bytes into a normal Python string for a JSON field or another text interface. If we accidentally use str on the bytes result, the output looks plausible in a log but includes representation syntax. Before sending the token in JSON, check that its type is str; calling str on the
- 03:30
bytes result does not convert its contents correctly. On the receiving side, validate and decode Base64 to recover bytes. Decode those bytes as UTF-8 only when the agreed payload is text; an image or zip file should stay binary. The worked examples on the page let you load the exact code into the console and compare the output. The practice function asks you to reproduce these boundaries, including a Unicode input, rather than memorizing a single token. The final run uses café, which is a better test than plain ASCII because its accented character occupies multiple bytes in UTF-8.
- 04:13
We encode it, decode the Base64 token with validation, and decode the recovered bytes as UTF-8. The terminal prints café again, proving that the two conversion pairs agree for this input. Next, we pass three at signs to b64decode with validate set to true. The decoder raises a binascii error and our example prints invalid base64. Without that validation, non-alphabet characters may be discarded, which can hide malformed input. A valid Base64 token can still contain invalid UTF-8 or an unexpected file format, so an application must check the decoded payload too.
- 04:56
As a final check, try encoding an empty string and another Unicode word on the lesson page. Explain the type at every stage before marking the practical task and quiz complete.
Understand the concept
Base64 is a representation for bytes, not a character encoding for arbitrary Python strings. The input to b64encode must be bytes, so encode text as UTF-8 first. Decode the resulting ASCII bytes only when you need a text token. This distinction matters whenever a JSON API, email attachment, or data URL transports binary content inside a text field. Base64 changes the representation; it does not encrypt or conceal the content.
A tempting mistake is to pass a str directly to b64encode or to turn the returned bytes into text with str(). The first raises TypeError; the second produces a Python bytes representation with a leading b and quotes. Neither gives a clean Base64 token. Inspect type() at each boundary: source text, UTF-8 bytes, encoded bytes, and finally ASCII token text. Naming each boundary makes the conversion easy to review.
The URL-safe functions replace the two characters that can be awkward in URL components, but they still return bytes. Use urlsafe_b64encode for a token that may appear in a URL and remember that the equals sign padding may remain. When decoding untrusted ordinary Base64, b64decode(..., validate=True) rejects characters outside the alphabet instead of silently discarding some of them. A successful Base64 decode does not prove the payload is valid text or safe data.
Round-trip a Unicode string to make both conversions visible: text to UTF-8 bytes, bytes to Base64, Base64 to bytes, and bytes back to UTF-8 text. Handle malformed input at the boundary where it enters the program. For a real credential use secrets rather than treating Base64 as security. In this exercise, the output is a reproducible encoding of public sample text and never a secret.
- Base64 transforms bytes, not str
- UTF-8 and Base64 solve different problems
- URL-safe Base64 still uses bytes and may have padding
- Base64 is not encryption
See it step by step
Read the code, predict the output, then compare it with the result.
01. Encode text through UTF-8
import base64
raw = 'Python'.encode('utf-8')
print(base64.b64encode(raw).decode('ascii'))
UHl0aG9uThe transport token is ASCII text, while the encoding function itself handles bytes.
02. Use the URL-safe alphabet
import base64
print(base64.urlsafe_b64encode(bytes([251, 255])).decode('ascii'))
-_8=The URL-safe variant substitutes hyphen and underscore for the usual plus and slash.
03. Reject malformed input
import base64
import binascii
try:
base64.b64decode('@@@', validate=True)
except binascii.Error:
print('invalid base64')
invalid base64Validation catches characters outside the Base64 alphabet instead of silently discarding them.
A closer look
Follow the reasoning, inspect each result, then try the suggested changes in the console below.
Cross from text to bytes
Base64 is a representation for bytes, not a character encoding for arbitrary Python strings. The input to b64encode must be bytes, so encode text as UTF-8 first. Decode the resulting ASCII bytes only when you need a text token. This distinction matters whenever a JSON API, email attachment, or data URL transports binary content inside a text field. Base64 changes the representation; it does not encrypt or conceal the content.
Run the first example and label every intermediate value. Python is text, while raw is a sequence of UTF-8 bytes. The Base64 operation transforms the latter and the final ASCII decode is only for presentation. Try replacing Python with café and observe that the token changes because the UTF-8 bytes change. The output is deterministic, which lets you compare results exactly.
import base64
raw = 'Python'.encode('utf-8')
print(base64.b64encode(raw).decode('ascii'))
UHl0aG9u- Encode source text as UTF-8 bytes.
- Apply Base64 to bytes and decode the result as ASCII.
Inspect every conversion boundary
A tempting mistake is to pass a str directly to b64encode or to turn the returned bytes into text with str(). The first raises TypeError; the second produces a Python bytes representation with a leading b and quotes. Neither gives a clean Base64 token. Inspect type() at each boundary: source text, UTF-8 bytes, encoded bytes, and finally ASCII token text. Naming each boundary makes the conversion easy to review.
The URL-safe variant is useful when encoded data travels in a URL component. It still does not encrypt the value, and it may still include equals-sign padding. Compare standard and URL-safe alphabets for the chosen two bytes. The final string is a transport representation, not a semantic value; decode and validate the underlying content at the receiving boundary.
import base64
print(base64.urlsafe_b64encode(bytes([251, 255])).decode('ascii'))
-_8=- Use the URL-safe function for URL components.
- Do not confuse URL-safe characters with secrecy.
Validate a token before trusting its payload
The URL-safe functions replace the two characters that can be awkward in URL components, but they still return bytes. Use urlsafe_b64encode for a token that may appear in a URL and remember that the equals sign padding may remain. When decoding untrusted ordinary Base64, b64decode(..., validate=True) rejects characters outside the alphabet instead of silently discarding some of them. A successful Base64 decode does not prove the payload is valid text or safe data.
The malformed sample is rejected before any application-specific interpretation. Without validate=True, the decoder may ignore non-alphabet characters. Once decoded, the bytes might still not be UTF-8, JSON, an image, or another expected format. Treat Base64 validation as the first of several checks, not as proof that the entire payload is safe or meaningful.
import base64
import binascii
try:
base64.b64decode('@@@', validate=True)
except binascii.Error:
print('invalid base64')
invalid base64- Decode with validation when input is untrusted.
- Validate the decoded payload separately.
Try it in Python
Edit the example and run it. Python starts in your browser the first time you click Run.
Python console
Ready to runNeed input()? Add one value per line
Your output appears here.
Need a hint?
Encode text with UTF-8, pass the bytes to base64.b64encode, then decode the resulting bytes with ASCII.
Complete the task and select Check task to verify your code.
Quick quiz
Three questions. You can change your answers and try again.
Typical mistakes
Everyone meets these errors. See what causes them and how to fix them.
Passing text directly
base64.b64encode('Python')base64.b64encode('Python'.encode('utf-8'))What happens: TypeError: a bytes-like object is required
The source text must be converted to bytes before a binary-to-text representation is applied.
Using str() on encoded bytes
str(base64.b64encode(b'Python'))base64.b64encode(b'Python').decode('ascii')What happens: The result contains a b prefix and quotation marks.
Decode the ASCII encoded bytes into an actual text token instead of formatting the bytes object for debugging.