Base64 Decode Python β€” b64decode() Guide

Β·Backend DeveloperΒ·Reviewed byDmitri VolkovΒ·Published

Use the free online Base64 Decode Online directly in your browser β€” no install required.

Try Base64 Decode Online Online β†’

When an API returns a content field that looks like eyJob3N0IjogImRiLXByb2Qi…, or your secrets manager hands you an encoded credential, or you need to extract a JWT payload β€” Python base64 decode is your first stop. The built-in base64module handles all of it, but the small details around bytes vs strings, URL-safe alphabets, and missing padding catch almost every developer at least once β€” I've debugged this particular category of errors in code reviews more times than I'd like to admit. This guide covers base64.b64decode(), urlsafe_b64decode(), automatic padding repair, decoding from files and HTTP responses, CLI tools, input validation, and four common mistakes with before/after fixes β€” all runnable Python 3.8+ examples. If you just need a quick one-off decode without writing code, ToolDeck's Base64 Decoder handles both standard and URL-safe Base64 instantly in your browser.

  • βœ“base64.b64decode(s) is built into Python stdlib β€” no install required; it always returns bytes, not str.
  • βœ“Chain .decode("utf-8") after b64decode() to convert bytes to a Python string β€” the function does not know the original text encoding.
  • βœ“For URL-safe Base64 (uses - and _ instead of + and /), use base64.urlsafe_b64decode() β€” standard in JWTs, OAuth tokens, and Google API credentials.
  • βœ“Fix the common "Incorrect padding" error with: padded = s + "=" * (-len(s) % 4) β€” adds 0, 1, or 2 chars as needed.
  • βœ“Set validate=True on any input from external sources to raise binascii.Error on non-Base64 characters instead of silently skipping them.

What is Base64 Decoding?

Base64 is an encoding scheme that represents arbitrary binary data as a string of 64 printable ASCII characters: A–Z, a–z, 0–9, +, and /, with = used as padding. Every 4 Base64 characters encode exactly 3 original bytes, so the encoded form is roughly 33% larger than the source. Decoding reverses the process β€” transforming the ASCII representation back into the original bytes.

Base64 does not encrypt data. It is purely a binary-to-text encoding β€” the encoded string is fully readable by anyone who runs it through a decoder:

Before β€” Base64 encoded

eyJob3N0IjogImRiLXByb2QubXljb21wYW55LmludGVybmFsIiwgInBvcnQiOiA1NDMyLCAidXNlciI6ICJhcHBfc3ZjIn0=

After β€” decoded

{"host": "db-prod.mycompany.internal", "port": 5432, "user": "app_svc"}

base64.b64decode() β€” Standard Library Decoding

Python's base64 module ships with the standard library β€” zero installation, always available. The primary function is base64.b64decode(s, altchars=None, validate=False). It accepts a str, bytes, or bytearray, and always returns bytes.

Minimal working example

Python 3.8+
import base64
import json

# Encoded database config received from a secrets manager
encoded_config = (
    "eyJob3N0IjogImRiLXByb2QubXljb21wYW55LmludGVybmFsIiwgInBvcnQiOiA1NDMyLCAid"
    "XNlciI6ICJhcHBfc3ZjIiwgInBhc3N3b3JkIjogInM0ZmVQYXNzITIwMjYifQ=="
)

# Step 1: decode Base64 bytes
raw_bytes = base64.b64decode(encoded_config)
print(raw_bytes)
# b'{"host": "db-prod.mycompany.internal", "port": 5432, "user": "app_svc", "password": "s4fePass!2026"}'

# Step 2: convert bytes β†’ str
config_str = raw_bytes.decode("utf-8")

# Step 3: parse into a dict
config = json.loads(config_str)
print(config["host"])    # db-prod.mycompany.internal
print(config["port"])    # 5432
Note:b64decode() always returns bytes β€” never a string. If the original data was text, chain .decode("utf-8"). If it was binary (an image, a PDF, a gzip archive), keep the bytes as-is and write them to a file or pass them directly to the consuming library.

Extended example: sort_keys, ensure_ascii, and strict validation

Python 3.8+
import base64
import binascii

# Token from an internal event bus β€” validate strictly (external input)
encoded_event = (
    "eyJldmVudCI6ICJvcmRlci5zaGlwcGVkIiwgIm9yZGVyX2lkIjogIk9SRC04ODQ3MiIsICJ"
    "0aW1lc3RhbXAiOiAiMjAyNi0wMy0xM1QxNDozMDowMFoiLCAicmVnaW9uIjogImV1LXdlc3QtMSJ9"
)

try:
    # validate=True raises binascii.Error on any non-Base64 character
    raw = base64.b64decode(encoded_event, validate=True)
    event = raw.decode("utf-8")
    print(event)
    # {"event": "order.shipped", "order_id": "ORD-88472", "timestamp": "2026-03-13T14:30:00Z", "region": "eu-west-1"}

except binascii.Error as exc:
    print(f"Invalid Base64: {exc}")
except UnicodeDecodeError as exc:
    print(f"Not UTF-8 text: {exc}")

Decoding URL-safe Base64 (base64url)

Standard Base64 uses + and /, which are reserved characters in URLs. The URL-safe variant (RFC 4648 Β§5, also called β€œbase64url”) replaces them with - and _. This is the encoding used in JWT tokens, OAuth 2.0 PKCE challenges, Google Cloud credentials, and most modern web authentication flows.

Passing URL-safe Base64 to b64decode() without adjusting the alphabet will silently corrupt data or raise binascii.Error. Use base64.urlsafe_b64decode() instead β€” it handles - β†’ +and _ β†’ / substitution automatically.

Python 3.8+
import base64
import json

# JWT payload segment (the middle part between the two dots)
# JWTs use URL-safe Base64 without trailing "=" padding
jwt_payload_b64 = (
    "eyJ1c2VyX2lkIjogMjg5MywgInJvbGUiOiAiYWRtaW4iLCAiaXNzIjogImF1dGgubXljb21w"
    "YW55LmNvbSIsICJleHAiOiAxNzQwOTAwMDAwLCAianRpIjogImFiYzEyMzQ1LXh5ei05ODc2In0"
)

# Restore padding before decoding (JWT deliberately omits '=')
padded = jwt_payload_b64 + "=" * (-len(jwt_payload_b64) % 4)

payload_bytes = base64.urlsafe_b64decode(padded)
payload = json.loads(payload_bytes.decode("utf-8"))

print(payload["role"])    # admin
print(payload["iss"])     # auth.mycompany.com
print(payload["user_id"]) # 2893
Note:The expression "=" * (-len(s) % 4) adds exactly 0, 1, or 2 padding characters as needed and is a no-op when the string is already correctly padded. It is the idiomatic Python fix for JWT and OAuth padding issues.

base64.b64decode() Parameters Reference

All parameters below apply to both b64decode() and urlsafe_b64decode(), except altchars which is only available on b64decode().

ParameterTypeDefaultDescription
sbytes | str | bytearrayβ€”The Base64-encoded input to decode; ASCII str is accepted alongside bytes types.
altcharsbytes | NoneNoneA 2-byte sequence substituting + and /; enables custom Base64 alphabets beyond the standard URL-safe variant.
validateboolFalseWhen True, raises binascii.Error on any character outside the Base64 alphabet; when False, non-alphabet bytes (newlines, spaces) are silently ignored.

The validate=False default is intentional for PEM-formatted data and multi-line Base64 (where newlines are common). For API payloads, user uploads, or any untrusted input, pass validate=True to catch corrupt or injected data early and surface a clear error.

Python Base64 Decode Padding Error β€” How to Fix It

The most frequent error when decoding Base64 in Python is:

Python 3.8+
import base64

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

Base64 requires string lengths that are multiples of 4. When data passes through URLs, HTTP headers, or JWT libraries, the trailing =padding is stripped to save bytes. There are two reliable ways to fix this.

Option 1: Restore padding inline (recommended)

Python 3.8+
import base64
import json

def b64decode_unpadded(data: str | bytes) -> bytes:
    """Decode Base64 with automatic padding correction."""
    if isinstance(data, str):
        data = data.encode("ascii")
    data += b"=" * (-len(data) % 4)
    return base64.b64decode(data)

# Works regardless of how many '=' were stripped
token_a = "eyJ0eXBlIjogImFjY2VzcyJ9"       # 0 chars of padding stripped
token_b = "eyJ0eXBlIjogInJlZnJlc2gifQ"      # 1 char stripped
token_c = "eyJ0eXBlIjogImFwaV9rZXkifQ=="    # already padded

for token in (token_a, token_b, token_c):
    result = json.loads(b64decode_unpadded(token).decode("utf-8"))
    print(result["type"])
# access
# refresh
# api_key

Option 2: URL-safe decode with padding for OAuth / JWT

Python 3.8+
import base64
import json

def decode_jwt_segment(segment: str) -> dict:
    """Decode a single JWT segment (header or payload)."""
    # Add padding, use URL-safe alphabet
    padded = segment + "=" * (-len(segment) % 4)
    raw = base64.urlsafe_b64decode(padded)
    return json.loads(raw.decode("utf-8"))

# Google OAuth ID token payload (simplified)
id_token_payload = (
    "eyJzdWIiOiAiMTEwNTY5NDkxMjM0NTY3ODkwMTIiLCAiZW1haWwiOiAic2FyYS5jaGVuQGV4"
    "YW1wbGUuY29tIiwgImhkIjogImV4YW1wbGUuY29tIiwgImlhdCI6IDE3NDA5MDAwMDB9"
)

claims = decode_jwt_segment(id_token_payload)
print(claims["email"])   # sara.chen@example.com
print(claims["hd"])      # example.com

Decode Base64 from a File and API Response

Reading Base64 from disk and decoding API payloads are the two most common production scenarios. Both warrant proper error handling β€” corrupt padding and unexpected binary types are real occurrences, not theoretical edge cases.

Reading and decoding a Base64 file

Python 3.8+
import base64
import json
from pathlib import Path

def decode_attachment(envelope_path: str, output_path: str) -> None:
    """
    Read a JSON envelope with a Base64-encoded attachment,
    decode it, and write the binary output to disk.
    """
    try:
        envelope = json.loads(Path(envelope_path).read_text(encoding="utf-8"))
        encoded_data = envelope["attachment"]["data"]
        file_bytes = base64.b64decode(encoded_data, validate=True)
        Path(output_path).write_bytes(file_bytes)
        print(f"Saved {len(file_bytes):,} bytes β†’ {output_path}")
    except FileNotFoundError:
        print(f"Envelope file not found: {envelope_path}")
    except (KeyError, TypeError):
        print("Unexpected envelope structure β€” 'attachment.data' missing")
    except base64.binascii.Error as exc:
        print(f"Invalid Base64 content: {exc}")

# Example envelope:
# {"attachment": {"filename": "invoice_2026_03.pdf", "data": "JVBERi0xLjQK..."}}
decode_attachment("order_ORD-88472.json", "invoice_2026_03.pdf")

Decoding Base64 from an HTTP API response

Python 3.8+
import base64
import json
import urllib.request

def fetch_and_decode_secret(vault_url: str, secret_name: str) -> str:
    """
    Retrieve a Base64-encoded secret from an internal vault API
    and return the decoded plaintext value.
    """
    url = f"{vault_url}/v1/secrets/{secret_name}"
    req = urllib.request.Request(url, headers={"X-Vault-Token": "s.internal"})

    try:
        with urllib.request.urlopen(req, timeout=5) as resp:
            body = json.loads(resp.read().decode("utf-8"))
            # Vault returns: {"data": {"value": "<base64>", "encoding": "base64"}}
            encoded = body["data"]["value"]
            return base64.b64decode(encoded).decode("utf-8")

    except urllib.error.URLError as exc:
        raise RuntimeError(f"Vault unreachable: {exc}") from exc
    except (KeyError, UnicodeDecodeError, base64.binascii.Error) as exc:
        raise ValueError(f"Unexpected secret format: {exc}") from exc

# db_pass = fetch_and_decode_secret("https://vault.internal", "db-prod-password")
# print(db_pass)  # s4feP@ss!2026
Note:If you use the requests library, replace urllib.request with resp = requests.get(url, timeout=5, headers=headers) and body = resp.json(). The Base64 decoding logic is identical.

Command-Line Base64 Decoding

For quick terminal inspection β€” verifying a token, peeking at an encoded config blob, or piping API output through a decoder β€” the base64command is available on Linux and macOS. Python's built-in -m base64 module works cross-platform including Windows.

Bash
# Decode a Base64 string and print the result (Linux / macOS)
echo "eyJob3N0IjogImRiLXByb2QubXljb21wYW55LmludGVybmFsIn0=" | base64 --decode
# {"host": "db-prod.mycompany.internal"}

# Decode a file, save decoded output
base64 --decode encoded_payload.txt > decoded_output.json

# Python's cross-platform CLI decoder (works on Windows too)
python3 -m base64 -d encoded_payload.txt

# Decode a JWT payload segment inline β€” strip header/signature first
echo "eyJ1c2VyX2lkIjogMjg5MywgInJvbGUiOiAiYWRtaW4ifQ" | python3 -c "
import sys, base64, json
s = sys.stdin.read().strip()
padded = s + '=' * (-len(s) % 4)
print(json.dumps(json.loads(base64.urlsafe_b64decode(padded)), indent=2))
"

For exploratory work where writing a shell pipeline feels like overkill, paste the string into the online Base64 Decoder β€” it auto-detects URL-safe input and fixes padding on the fly.

Validating Base64 Input Before Decoding

When Base64 data arrives from user input, a webhook, or an untrusted third-party API, validate it before decoding to surface clean, actionable errors instead of confusing binascii.Error tracebacks deep inside business logic. Python gives you two approaches: catch exceptions, or pre-validate with a regex.

Python 3.8+
import base64
import binascii
import re

# ── Option A: try/except (recommended for most code paths) ──────────────────

def safe_b64decode(data: str) -> bytes | None:
    """Return decoded bytes, or None if the input is not valid Base64."""
    try:
        padded = data + "=" * (-len(data) % 4)
        return base64.b64decode(padded, validate=True)
    except (binascii.Error, ValueError):
        return None

print(safe_b64decode("not-base64!!"))                     # None
print(safe_b64decode("eyJ0eXBlIjogInJlZnJlc2gifQ"))      # b'{"type": "refresh"}'


# ── Option B: regex pre-validation ──────────────────────────────────────────

# Standard Base64 (alphabet: A-Z a-z 0-9 + /)
_STANDARD_RE = re.compile(r"^[A-Za-z0-9+/]*={0,2}$")

# URL-safe Base64 (alphabet: A-Z a-z 0-9 - _)
_URLSAFE_RE = re.compile(r"^[A-Za-z0-9-_]*={0,2}$")

def is_valid_base64(s: str) -> bool:
    """True if s is a syntactically valid standard Base64 string."""
    # Length must be a multiple of 4 for fully padded strings
    stripped = s.rstrip("=")
    padded = stripped + "=" * (-len(stripped) % 4)
    return bool(_STANDARD_RE.match(padded))

print(is_valid_base64("SGVsbG8gV29ybGQ="))   # True
print(is_valid_base64("SGVsbG8gV29ybGQ!"))   # False  (! is not Base64)

High-Performance Alternative: pybase64

For the vast majority of use cases, Python's stdlib base64 module is entirely adequate. If you are processing thousands of API payloads per second, decoding multi-megabyte binary attachments in a tight loop, or your profiler shows Base64 operations as a hotspot β€” consider pybase64. It is a C-extension wrapper around libbase64 and is typically 2–5Γ— faster than the stdlib implementation on large inputs.

Bash
pip install pybase64
Python 3.8+
import pybase64

# Drop-in replacement β€” identical API to the stdlib base64 module
encoded_image = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQI12NgAAIABQ..."

image_bytes = pybase64.b64decode(encoded_image, validate=False)
print(f"Decoded {len(image_bytes):,} bytes")

# URL-safe variant β€” same as base64.urlsafe_b64decode()
token_bytes = pybase64.urlsafe_b64decode("eyJpZCI6IDQ3MX0=")
print(token_bytes)  # b'{"id": 471}'

# Benchmark note: on strings under ~10 KB the function-call overhead dominates
# and the speedup is negligible. Profile before switching.

The API is intentionally identical to base64 β€” swap the import and nothing else changes. Use it only when profiling confirms that Base64 is actually a bottleneck, which is uncommon outside of high-throughput data pipelines.

Common Mistakes

I've seen these four errors in code reviews repeatedly β€” they are especially common among developers coming from languages like JavaScript or PHP where Base64 decode returns a string directly, or from tutorials that skip error handling entirely.

Mistake 1: Forgetting to call .decode() on the result

Before Β· Python
After Β· Python
# ❌ b64decode() returns bytes β€” this crashes downstream
import base64

raw = base64.b64decode("eyJ1c2VyX2lkIjogNDcxLCAicm9sZSI6ICJhZG1pbiJ9")

# TypeError: byte indices must be integers or slices, not str
user_id = raw["user_id"]
# βœ… decode bytes β†’ str, then parse
import base64, json

raw = base64.b64decode("eyJ1c2VyX2lkIjogNDcxLCAicm9sZSI6ICJhZG1pbiJ9")
payload = json.loads(raw.decode("utf-8"))
print(payload["user_id"])  # 471
print(payload["role"])     # admin

Mistake 2: Using b64decode() on URL-safe Base64 input

Before Β· Python
After Β· Python
# ❌ JWT and OAuth tokens use '-' and '_' β€” not in standard alphabet
import base64

jwt_segment = "eyJ1c2VyX2lkIjogMjg5M30"
# binascii.Error or silently wrong bytes β€” unpredictable behaviour
base64.b64decode(jwt_segment)
# βœ… use urlsafe_b64decode() for any token with '-' or '_'
import base64, json

jwt_segment = "eyJ1c2VyX2lkIjogMjg5M30"
padded = jwt_segment + "=" * (-len(jwt_segment) % 4)
data = base64.urlsafe_b64decode(padded)
print(json.loads(data.decode("utf-8")))
# {'user_id': 2893}

Mistake 3: Not fixing padding on stripped tokens

Before Β· Python
After Β· Python
# ❌ JWTs and most URL-transmitted tokens strip '=' β€” this crashes
import base64

# Valid JWT payload segment β€” no padding, as per spec
segment = "eyJ0eXBlIjogImFjY2VzcyIsICJqdGkiOiAiMzgxIn0"
base64.urlsafe_b64decode(segment)
# binascii.Error: Incorrect padding
# βœ… add padding before every urlsafe_b64decode() call
import base64, json

segment = "eyJ0eXBlIjogImFjY2VzcyIsICJqdGkiOiAiMzgxIn0"
padded = segment + "=" * (-len(segment) % 4)
result = json.loads(base64.urlsafe_b64decode(padded).decode("utf-8"))
print(result["type"])  # access
print(result["jti"])   # 381

Mistake 4: Calling .decode("utf-8") on binary data

Before Β· Python
After Β· Python
# ❌ Binary files (PDF, PNG, ZIP) are not UTF-8 text β€” this crashes
import base64

# Base64-encoded PDF starts with JVBERi... (%PDF-)
pdf_b64 = "JVBERi0xLjQKJeLjz9MKNyAwIG9iago8PC9U..."
pdf_text = base64.b64decode(pdf_b64).decode("utf-8")
# UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe2
# βœ… write binary directly to a file β€” no .decode() needed
import base64
from pathlib import Path

pdf_b64 = "JVBERi0xLjQKJeLjz9MKNyAwIG9iago8PC9U..."
pdf_bytes = base64.b64decode(pdf_b64)
Path("report_q1_2026.pdf").write_bytes(pdf_bytes)
print(f"Saved {len(pdf_bytes):,} bytes")

Decoding Large Base64 Files in Python

Loading a 200 MB Base64 file with Path.read_text() and decoding it in one call will allocate the encoded string, the decoded bytes, and any intermediate representations simultaneously β€” easily exhausting memory on constrained servers or Lambda functions. For files larger than ~50–100 MB, use a chunked approach instead.

Chunked decoding to disk (no full-file RAM load)

Python 3.8+
import base64

def decode_large_b64_file(input_path: str, output_path: str, chunk_size: int = 65536) -> None:
    """
    Decode a large Base64 file in chunks to avoid loading the entire encoded
    string into memory. chunk_size must be a multiple of 4 to keep Base64
    block boundaries aligned across reads.
    """
    assert chunk_size % 4 == 0, "chunk_size must be a multiple of 4"

    bytes_written = 0
    with open(input_path, "rb") as src, open(output_path, "wb") as dst:
        while True:
            chunk = src.read(chunk_size)
            if not chunk:
                break
            # Strip whitespace that may appear in wrapped/multiline Base64
            chunk = chunk.strip()
            if chunk:
                dst.write(base64.b64decode(chunk))
                bytes_written += len(chunk)

    print(f"Decoded {bytes_written:,} Base64 bytes β†’ {output_path}")

# Example: decode a 300 MB database snapshot stored as Base64
decode_large_b64_file("snapshot_2026_03_13.b64", "snapshot_2026_03_13.sql.gz")

Decoding Base64 with base64.decodebytes() for PEM / multiline data

Python 3.8+
import base64

# base64.decodebytes() is designed for MIME / PEM Base64 that wraps at 76 chars.
# It silently ignores whitespace and newlines β€” perfect for certificate files.

with open("server_cert.pem", "rb") as f:
    pem_data = f.read()

# Strip PEM headers if present, then decode
lines = [
    line for line in pem_data.splitlines()
    if not line.startswith(b"-----")
]
raw_cert = base64.decodebytes(b"
".join(lines))
print(f"Certificate DER payload: {len(raw_cert):,} bytes")
Note:Use base64.decodebytes() for PEM certificates, MIME attachments, and any Base64 that wraps at fixed line widths. Use the chunked approach above for large opaque blobs (backups, media files). For compact, single-line tokens (JWT, OAuth), b64decode() or urlsafe_b64decode() is always the right choice.

Python Base64 Decoding Methods β€” Quick Comparison

MethodAlphabetPaddingOutputRequires InstallBest For
base64.b64decode()Standard (A–Z a–z 0–9 +/)RequiredbytesNo (stdlib)General-purpose, email, PEM
base64.decodebytes()Standard (A–Z a–z 0–9 +/)Ignored (strips whitespace)bytesNo (stdlib)PEM certs, MIME attachments, multiline Base64
base64.urlsafe_b64decode()URL-safe (A–Z a–z 0–9 -_)RequiredbytesNo (stdlib)JWT, OAuth, Google Cloud APIs
base64.b32decode()32-char (A–Z, 2–7)RequiredbytesNo (stdlib)TOTP secrets, DNS-safe IDs
base64.b16decode()Hex (0–9, A–F)NonebytesNo (stdlib)Hex-encoded checksums, hashes
pybase64.b64decode()Standard (A–Z a–z 0–9 +/)RequiredbytesYes (pip)High-throughput pipelines, large payloads
CLI: base64 --decodeStandardAutostdoutNo (system)Quick terminal inspection

Use b64decode() as your default. Switch to urlsafe_b64decode()the moment you see - or _ in the input β€” those characters are the unmistakable sign of URL-safe Base64. Reach for pybase64 only after profiling confirms a bottleneck. For one-off checks during development, ToolDeck's Base64 Decoder handles both alphabets and auto-repairs padding β€” no Python environment needed.

Frequently Asked Questions

How do I decode a Base64 string to a regular string in Python?

Call base64.b64decode(encoded) to get bytes, then call .decode("utf-8")on the result to get a Python str. The two steps are always separate because b64decode() only reverses the Base64 alphabet β€” it does not know whether the original content was UTF-8, Latin-1, or binary. If the data uses a non-UTF-8 encoding, pass the correct codec name to .decode(), for example .decode("latin-1").

Why do I get β€œIncorrect padding” when decoding Base64 in Python?

Base64 strings must be a multiple of 4 characters long. JWTs, OAuth tokens, and data transmitted in URLs often strip the trailing = padding. Fix it by appending "=" * (-len(s) % 4) before decoding. This formula adds exactly 0, 1, or 2 characters as needed, and is a safe no-op when the string is already correctly padded.

What is the difference between b64decode() and urlsafe_b64decode() in Python?

Both decode the same Base64 algorithm but with different alphabets for the 62nd and 63rd characters. b64decode() uses + and /; urlsafe_b64decode() uses - and _. The URL-safe variant is defined in RFC 4648 Β§5 and is used wherever Base64 must survive in URLs, HTTP headers, or cookie values without percent-encoding. Mixing them up causes either a binascii.Error or silently corrupt output.

How do I decode a Base64-encoded image in Python?

Decode to bytes with base64.b64decode(encoded), then write those bytes directly to a file β€” do not call .decode("utf-8") on image data. If the input is a data URL (e.g. data:image/png;base64,iVBORw0KGgo…), strip the prefix first:

Python 3.8+
import base64
from pathlib import Path

# Data URL from an <img src="..."> or an API response
data_url = (
    "data:image/png;base64,"
    "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQI12NgAAIABQ=="
)

# Split off the "data:image/png;base64," prefix
_, encoded = data_url.split(",", 1)
image_bytes = base64.b64decode(encoded)
Path("avatar_jsmith.png").write_bytes(image_bytes)
print(f"Saved {len(image_bytes)} bytes")

Can I decode Base64 in Python without importing any module?

Technically yes, but there is no reason to. The base64module is part of Python's standard library, always available, always installed β€” it has no dependencies and its functions are implemented in C. Reimplementing Base64 from scratch would be slower, more error-prone, and harder to maintain. Always use import base64.

How do I decode Base64 in Python when the input is bytes, not a string?

base64.b64decode() accepts str, bytes, and bytearray interchangeably β€” no conversion required. If you receive b"SGVsbG8=" from a socket or file read, pass it directly. Padding repair works the same way with bytes: data + b"=" * (-len(data) % 4) when operating in bytes mode.

  • Base64 Encode β€” encode text or binary files to Base64 instantly; useful for generating test fixtures for your Python decoding code without running a script.
  • JWT Decoder β€” inspect JWT header and payload without writing code; the payload is decoded with URL-safe Base64 under the hood, exactly as shown in the examples above.
  • URL Decode β€” percent-decode query strings and path segments; often needed alongside Base64 decoding when parsing OAuth callback URLs or webhook payloads.
  • URL Encode β€” percent-encode special characters; handy when you need to embed a Base64-encoded value safely inside a URL query parameter.
Also available in:JavaScriptGoJavaC#
MS
Maria SantosBackend Developer

Maria is a backend developer specialising in Python and API integration. She has broad experience with data pipelines, serialisation formats, and building reliable server-side services. She is an active member of the Python community and enjoys writing practical, example-driven guides that help developers solve real problems without unnecessary theory.

DV
Dmitri VolkovTechnical Reviewer

Dmitri is a DevOps engineer who relies on Python as his primary scripting and automation language. He builds internal tooling, CI/CD pipelines, and infrastructure automation scripts that run in production across distributed teams. He writes about the Python standard library, subprocess management, file processing, encoding utilities, and the practical shell-adjacent Python that DevOps engineers use every day.