Using Base64 in REST and GraphQL APIs
When architecting a modern API, developers are primarily tasked with moving structured text—usually formatted as JSON or XML—between a client and a server. But what happens when the API needs to accept or return a binary file, like a PDF report or a user avatar? Because text-based APIs natively reject raw binary data, developers must utilize Base64 encoding to format the data safely.
In this guide, we will explore the architectural patterns, security considerations, and performance impacts of utilizing Base64 within API payloads.
The Transport Problem
REST and GraphQL APIs overwhelmingly use JSON as their payload format. By definition, the JSON specification only permits valid Unicode strings, numbers, booleans, and structural brackets. It has absolutely zero capacity to represent raw 8-bit binary data.
If you attempt to force raw binary bytes into a JSON string, the parser on the receiving end will encounter invalid control characters and immediately throw a syntax error, terminating the request. To bypass this, the binary data must be serialized into a compliant text string. This is where the Base64 Encoder becomes critical infrastructure.
Common API Use Cases for Base64
1. File Uploads in JSON APIs
While multipart/form-data is the traditional method for file uploads, many modern single-page applications (SPAs) prefer the simplicity of sending a single JSON payload that contains both the relational metadata and the file data.
POST /api/v1/users/123/documents
Content-Type: application/json
{
"documentType": "passport",
"expirationDate": "2030-01-01",
"fileMimeType": "application/pdf",
"fileData": "JVBERi0xLjcKCjEgMCBvYmogICUgZW50cnkgcG9pbnQKPDw..."
}
The backend API receives this JSON, extracts the fileData string, passes it through a Base64 decoder, and stores the resulting raw binary PDF in an object storage bucket (like AWS S3).
2. Basic Access Authentication
Base64 is hardcoded into the HTTP protocol itself for legacy authentication. When utilizing Basic Auth, the client constructs a string containing the username and password separated by a colon (user:password), encodes the entire string to Base64, and injects it into the HTTP headers:
Authorization: Basic dXNlcjpwYXNzd29yZA==
Security Warning: As discussed in our Base64 vs Encryption guide, this provides zero security. Basic Auth must strictly be used over an encrypted HTTPS connection.
3. JSON Web Tokens (JWT)
Almost all modern APIs rely on JWTs for stateless authorization. A JWT is composed of three JSON objects/hashes that have been serialized using a specific URL-safe variant of Base64 known as Base64URL. APIs use this encoding to safely pass complex token payloads within the Authorization: Bearer header without causing parsing errors.
Performance Implications (The 33% Tax)
The primary architectural drawback of using Base64 in an API is the inherent data inflation. Because the algorithm maps 3 bytes of raw data into 4 characters of text, the payload size increases by approximately 33%.
For small files (under 1MB), this inflation is trivial and the developer experience of utilizing a single JSON payload outweighs the bandwidth cost. However, for large files, this inflation becomes a massive bottleneck. A 50MB video file becomes a 66MB text string. Not only does this waste network bandwidth, but the API server must load that entire 66MB string into memory just to parse the JSON request, which can quickly lead to Out-Of-Memory (OOM) crashes under heavy load.
Best Practices
- Enforce Size Limits: If your API accepts Base64 encoded files via JSON, strictly enforce payload size limits (e.g., maximum 5MB) at your API Gateway or reverse proxy to prevent memory exhaustion attacks.
- Separate Data URI Prefixes: Instruct clients to send the raw Base64 string without the
data:image/png;base64,prefix. Store the MIME type in a separate JSON field. This saves the backend from performing expensive string-splitting operations before decoding. - Use Multipart for Large Files: If your application needs to handle large media uploads, abandon JSON for that specific endpoint and implement streaming
multipart/form-datarequests.