Base64 Encode and Decode in Python
Python ships Base64 in the standard library.
The base64 module handles standard and URL-safe encoding, works with bytes objects, and requires no third-party packages , import base64 is all you need for encoding binary files, building HTTP Basic Auth headers, and packing binary data into JSON payloads.1
Core API and encoding variants
Python exposes four functions in the standard library base64 module: b64encode() and b64decode() for standard Base64, and urlsafe_b64encode() and urlsafe_b64decode() for URL-safe Base64 (- and _ replacing + and /). Both sets require bytes input, which means you must explicitly convert strings before calling any of these functions.2
Choosing standard or URL-safe encoding
Use standard Base64 when the output stays in controlled text fields, such as JSON properties or PEM-like blocks. Choose URL-safe Base64 when the value enters URLs, filenames, cookies, or JWT-style tokens where + and / need extra handling. This choice prevents client code from applying percent-encoding after the fact. Consequently, the call pattern is always base64.b64encode(text.encode('utf-8')).decode() for string encoding. URL-safe output never contains + or / characters, making it safe for JWT payloads, URL parameters, and filenames.3 Furthermore, b64decode() accepts padded or unpadded input and handles both standard and URL-safe input if you substitute characters first. For file workflows, read bytes first and keep the encoded string in memory only until it reaches the API or file that requested it.
The standard and URL-safe helpers share the same four-function shape, so moving a feature from one to the other is usually a one-line change once the input is already bytes. Teams that wrap both behind a single encode helper make the URL-safe decision explicit at each call site instead of leaving it implicit across scattered b64encode calls.
Working with files and binary data
Reading a file in binary mode and passing the bytes directly to b64encode() handles any file type: images, PDFs, archives. For very large files, process in chunks of 3 × N bytes (multiples of 3 preserve block alignment across chunks).3 The binascii module exposes a2b_base64() and b2a_base64() for streaming scenarios where you write each chunk to a file or network stream.4 Furthermore, base64.encodebytes() wraps output at 76 characters with newlines , useful for PEM-style encoding , while b64encode() produces a single unbroken string.2 When you encode a multi-megabyte image for a JSON API upload, the chunked approach prevents the script from holding both the raw file bytes and the full Base64 string in memory simultaneously, which matters on memory-constrained containers and serverless functions where exceeding the allocation limit produces a hard kill rather than a graceful error.
Security and common mistakes
Base64 is encoding, not encryption. Anyone who receives a Base64 string can decode it with no key, which means it offers zero protection for sensitive values like passwords, API keys, or personally identifiable information. Consequently, never use Base64 as a security measure; it exists solely to make binary data safe for text-based transport.
Checking decoded bytes before use
The most frequent mistake is encoding Unicode strings without first converting to bytes: base64.b64encode('hello') raises TypeError because the function does not accept str. Always call .encode('utf-8') on the string first, then pass the resulting bytes to b64encode(). Validate decoded binary data before passing it to parsers, because an attacker who controls the Base64 input can encode malformed bytes that crash image decoders or XML parsers in downstream services. For URL-safe contexts, always use the urlsafe_ variants rather than substituting characters manually. A practical validation step is to check the first few decoded bytes against known magic byte sequences for the expected file format, which catches the case where a client sends a crafted payload that decodes without error but contains a different file type than declared.
Decoding and validating untrusted Base64 input
When accepting Base64 input from untrusted sources, Python's base64.b64decode() does not raise an error for all invalid inputs by default. Setting validate=True changes this: the function raises binascii.Error for any character outside the standard Base64 alphabet, including whitespace and URL-safe characters (- and _).5 Without validate=True, invalid characters are silently ignored and the decoder produces output from whatever valid characters it finds.5
Handling binascii.Error in production code
The recommended pattern for API endpoints: try: decoded = base64.b64decode(data, validate=True) except binascii.Error as e: raise ValueError(f'Invalid Base64 input: {e}'). After decoding, verify the byte length and inspect the magic bytes (first 4 to 8 bytes) before passing the result to image decoders, ZIP parsers, or any function that interprets binary content. A Base64 string that decodes without errors may still contain malformed binary data crafted to crash a downstream parser.
Base64 in Django and FastAPI responses
In Django REST Framework, binary fields in serializers often use a custom SerializerMethodField that calls base64.b64encode(instance.file_field.read()).decode(). For file upload endpoints, Django's InMemoryUploadedFile.read() returns bytes that pass directly to b64encode without any charset conversion step. FastAPI uses Pydantic models: define binary response fields as str in the model and call base64.b64encode(bytes_value).decode() in the endpoint function before returning.
For URL-safe contexts in web frameworks, use base64.urlsafe_b64encode(data).rstrip(b'=').decode() and document this encoding explicitly in your OpenAPI schema so clients know which variant to decode with. Both Django and FastAPI parse request JSON before your code runs, so a Base64 string in a request body arrives as a Python str. Convert with .encode('utf-8') before passing to b64decode when the string may contain non-ASCII characters from a non-standard encoder.
When to use this
Use Python's base64 module when you need to encode binary files, build HTTP Basic Auth headers, create data URIs, or pack binary data into JSON strings. Use urlsafe_b64encode for JWTs, URL parameters, and filenames.
Notes
Import with import base64. The module provides b64encode() and b64decode() for standard Base64, and urlsafe_b64encode() and urlsafe_b64decode() for URL-safe variants. All functions accept bytes and return bytes , call .decode('utf-8') to get a string. For file encoding, read the file in binary mode and pass the bytes directly.
Examples
Encode a string
import base64 encoded = base64.b64encode(b"Hello, World!") print(encoded) # b'SGVsbG8sIFdvcmxkIQ=='
Decode a string
import base64
decoded = base64.b64decode("SGVsbG8sIFdvcmxkIQ==")
print(decoded)
# b'Hello, World!' URL-safe encoding
import base64 encoded = base64.urlsafe_b64encode(b"user+name/email") print(encoded) # b'dXNlcituYW1lL2VtYWls'
Encode a file
import base64
with open("image.png", "rb") as f:
encoded = base64.b64encode(f.read())
print(f"{len(encoded)} bytes") Verify with the Base64 Text & File Encoder/Decoder tool.
Encode a string
import base64 encoded = base64.b64encode(b"Hello, World!") print(encoded) # b'SGVsbG8sIFdvcmxkIQ=='
Code says: SGVsbG8sIFdvcmxkIQ==
- 1.
Python Software Foundation, "cpython/Doc/library/base64.rst," github.com, accessed June 2026. https://github.com/python/cpython/blob/main/Doc/library/base64.rst
- 2.
Python Software Foundation, "base64 , Base16, Base32, Base64, Base85 Data Encodings," docs.python.org, accessed June 2026. https://docs.python.org/3/library/base64.html
- 3.
S. Josefsson, "RFC 4648: The Base16, Base32, and Base64 Data Encodings," RFC 4648, IETF, October 2006. https://www.rfc-editor.org/rfc/rfc4648
- 4.
Python Software Foundation, "cpython/Doc/library/binascii.rst," github.com, accessed June 2026. https://github.com/python/cpython/blob/main/Doc/library/binascii.rst
- 5.
Python Software Foundation, "base64 , Base16, Base32, Base64, Base85 Data Encodings," docs.python.org, 2023. https://docs.python.org/release/3.11.5/library/base64.html
Standard Base64 uses + and / characters. URL-safe Base64 replaces these with - and _ so the output can be used in URL query parameters and filenames without additional percent-encoding.
Yes. b64encode() adds = padding by default. If you need to strip it (for JWT payloads, for example), use .rstrip(b"="). When decoding, Python accepts both padded and unpadded input.
For very large files, use the encode() and decode() functions from the base64 module with file handles, or process in chunks. The standard b64encode() function requires the full content in memory.
No. Base64 is encoding; anyone can decode it with no key. It is used to represent binary data as text, not to protect it. CapyToolkit keeps browser-based encoding local, so you can compare a small Python sample without uploading test data.
Validate Base64 at trust boundaries, especially API uploads or user-provided files. Use validate=True, then inspect the decoded bytes before passing them to image, archive, or document parsers. CapyToolkit follows the same local-only principle for browser-based checks.
Base64 Encode and Decode in JavaScript
In JavaScript, Base64 depends on runtime: browsers expose btoa() and atob(), while Node.js relies on Buffer.
Browsers expose btoa() and atob() as globals, but btoa() only handles Latin-1 characters; characters with Unicode code points above 255 throw a DOMException.1 For full Unicode support and Node.js server-side use, Buffer.from() and its toString('base64') method handle any byte sequence without restrictions.2
Core API and encoding variants
btoa() encodes a Latin-1 string to Base64, and atob() decodes Base64 back to a Latin-1 string, but neither function handles characters outside the 0x00 to 0xFF range without throwing a DOMException that halts script execution in the calling context.1 This limitation is the single most common source of Base64 errors in browser JavaScript.
Choosing the right JavaScript path
Use btoa() only when your browser input is ASCII or Latin-1. The safer habit is to choose the path from the runtime first: browser Latin-1, browser Unicode, or Node.js Buffer. For modern text, TextEncoder converts the string to UTF-8 bytes before the binary-string step, while Buffer.from() remains the simplest server-side choice. For Unicode, use TextEncoder to convert the string to UTF-8 bytes first, then convert those bytes to a binary string for btoa(). In Node.js, Buffer.from(str).toString('base64') handles any encoding including UTF-8 without the Latin-1 restriction that limits browser-based encoding. Consequently, the btoa()/atob() path works for ASCII-only data; the TextEncoder/Buffer path works for all text. Furthermore, the modern fromBase64() and toBase64() methods on Uint8Array offer a cleaner API for binary data in supporting runtimes.
The same runtime-first habit also keeps the decode path predictable, because the function you call to encode is the one whose inverse you reach for when reading the value back. Matching encode and decode variants at both ends avoids the silent corruption that appears when standard output is fed to a URL-safe decoder that rejects the plus and slash characters.
Working with files and binary data
File encoding in browsers uses the FileReader API: reader.readAsDataURL(file) returns a data URI with Base64-encoded content, prefixed with the MIME type and encoding marker such as data:image/png;base64, that you must strip before using the raw Base64 string in any downstream processing.3 The prefix format is always data:[mediatype];base64, followed by the encoded bytes.
Handling browser files and Node streams
Strip the data:*/*;base64, prefix to get raw Base64. For the modern approach, file.arrayBuffer() returns an ArrayBuffer; convert to Uint8Array, then to a binary string for btoa(). In Node.js, fs.readFileSync(path) returns a Buffer, and buf.toString('base64') handles encoding in one call without any character-set restrictions. Furthermore, for streaming large files in Node.js, pipe the file stream through a base64 encoding transform stream rather than loading the entire file into memory. This streaming approach keeps memory usage constant regardless of file size, because each chunk is encoded and flushed to the output before the next chunk is read from disk. For files over one megabyte, the chunked approach also prevents the main thread from blocking during the encode step, which keeps the event loop free to handle incoming requests in server-side code.
Security and common mistakes
Base64 is encoding, not protection. btoa() output is readable by anyone, which means it provides zero security for credentials, authentication tokens, or sensitive user data that must remain confidential in transit or at rest. Treat every Base64 string as public information that any observer can decode without effort or special tools.
Avoiding runtime-specific traps
The most frequent mistake is passing a non-Latin-1 string to btoa() directly: btoa('café') throws a DOMException because é is outside the Latin-1 range. Always route non-ASCII input through TextEncoder. In Node.js, the reverse mistake is calling atob() on a Buffer.toString('base64') output containing URL-safe characters (- and _); atob() throws on those characters. Match the encoding variant (standard vs URL-safe) at both ends. A second common trap is assuming that Base64 output is safe for any text context without checking the target format. HTTP headers must be single-line strings, so any Base64 output that includes line breaks from wrapping will cause silent truncation at the first newline. Always strip or disable line wrapping before inserting Base64 into header values, JSON string properties, or cookie values where newline characters have special meaning.
The Uint8Array.fromBase64 and toBase64 methods
The TC39 Stage 4 proposal for Uint8Array.fromBase64() and Uint8Array.prototype.toBase64() provides a clean, native API for Base64 without the binary-string workaround that btoa() requires.4 Uint8Array.fromBase64('SGVsbG8=') returns a Uint8Array directly. new Uint8Array([72, 101, 108, 108, 111]).toBase64() returns 'SGVsbG8='. Both methods accept an options object with an alphabet property set to either 'base64' or 'base64url'.
For environments that do not yet ship these methods, feature-detect before use: if (typeof Uint8Array.fromBase64 === 'function') { /* fast path */ } else { /* Buffer or btoa fallback */ }. This guard keeps your encoding logic behind a single conditional rather than branching every call site. A polyfill exists for older runtimes; install it only in environments where the check returns false to avoid duplicating the native implementation.
Base64 in Service Workers and the Cache API
Service Workers intercept network requests from a page and can transform request and response bodies before they reach the browser or a remote server.5 Encoding binary responses as Base64 inside a Service Worker lets you cache binary data as a string in the Cache API, which stores Response objects for later retrieval. The pattern: intercept the fetch event, read the response as ArrayBuffer, encode the bytes to Base64 using the binary-string conversion, then cache the resulting string as a synthetic JSON response.
Reading the cached value later reverses the process: retrieve the cached JSON string, decode with atob(), convert each character code to a byte with Uint8Array.from, and reconstruct the original ArrayBuffer. Because Service Workers run in a background context separate from the main page context, the encoding and decoding work does not block the UI. This approach is useful for offline-first apps that cache audio or image files that the Cache API would otherwise evict under storage pressure.
When to use this
Use Buffer.from() in Node.js for all string and file encoding , it handles Unicode and binary natively. Use btoa() in browser scripts only when you can guarantee Latin-1 input. Use the TextEncoder pattern for browser Unicode encoding without external dependencies.
Notes
btoa() encodes a Latin-1 string to Base64. atob() decodes Base64 back to Latin-1. For Unicode, use a combination of encodeURIComponent + btoa, or TextEncoder + btoa with binary string conversion. In Node.js, Buffer.from(str, 'base64') and buf.toString('base64') handle all cases including binary.
Examples
Browser: encode ASCII
const encoded = btoa("Hello, World!");
console.log(encoded);
// "SGVsbG8sIFdvcmxkIQ==" btoa() only works with Latin-1 characters.
Browser: encode Unicode
const encoded = btoa(
encodeURIComponent("Héllo Wörld").replace(
/%([0-9A-F]{2})/g,
(_, p1) => String.fromCharCode("0x" + p1)
)
); This workaround converts Unicode to percent-encoded Latin-1 before btoa().
Node.js: encode
const encoded = Buffer.from("Héllo Wörld").toString("base64");
console.log(encoded);
// "SMOpbGxvIFfDtnJsZA==" Buffer handles Unicode natively.
Node.js: decode
const decoded = Buffer.from("SMOpbGxvIFfDtnJsZA==", "base64").toString();
console.log(decoded);
// "Héllo Wörld" Verify with the Base64 Text & File Encoder/Decoder tool.
Browser: encode ASCII
const encoded = btoa("Hello, World!");
console.log(encoded);
// "SGVsbG8sIFdvcmxkIQ==" btoa() only works with Latin-1 characters.
Code says: SGVsbG8sIFdvcmxkIQ==
- 1.
MDN Contributors, "Window: btoa() method," developer.mozilla.org, 2025. https://developer.mozilla.org/en-US/docs/Web/API/Window/btoa
- 2.
Node.js Foundation, "Buffer," nodejs.org, accessed June 2026. https://nodejs.org/api/buffer.html
- 3.
MDN Contributors, "FileReader: readAsDataURL() method," developer.mozilla.org, 2025. https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL
- 4.
TC39, "Base64 in JavaScript proposal," tc39.es, accessed June 2026. https://tc39.es/proposal-arraybuffer-base64/
- 5.
World Wide Web Consortium, "Service Workers Nightly," w3.org, June 2026. https://www.w3.org/TR/service-workers/
btoa() only accepts characters in the Latin-1 range (0x00–0xFF). Characters like é, ö, or any non-Latin character fall outside this range and throw an error. Use the encodeURIComponent workaround or switch to Node.js Buffer.
btoa() is a browser function that works with Latin-1 strings. Buffer.from() is Node.js and handles any encoding including UTF-8. For isomorphic code, use a library like js-base64 or the modern Uint8Array approach.
Read the file as an ArrayBuffer using FileReader, then convert to a binary string or Uint8Array before passing to btoa(). For large files, use a chunked approach to avoid memory issues.
No. Base64 is reversible encoding, not hashing or encryption. Anyone can decode it. Use bcrypt, scrypt, or Argon2 for password hashing. CapyToolkit processes all data locally in your browser.
Prefer Buffer in Node.js because it accepts UTF-8 text, file buffers, and binary values without the Latin-1 limitation. Keep btoa() for small browser-only strings, and use TextEncoder when Unicode text must survive the browser path.
Base64 Encode and Decode in Java
Java keeps Base64 choices explicit through java.util.Base64.
The java.util.Base64 class provides three encoder/decoder instances: basic (standard), URL-safe, and MIME. All of them accept byte arrays natively and suit encoding binary data, API payloads, and file content without third-party dependencies.1
Core API and encoding variants
Java provides three encoder instances through java.util.Base64: getEncoder() for standard RFC 4648 Base64, getUrlEncoder() for URL-safe Base64 (replacing + with - and / with _), and getMimeEncoder() for MIME-formatted output (76-character lines with CRLF). Each encoder exposes encodeToString(byte[]) and encode(byte[]) methods, and all three follow the same API pattern so switching between them requires changing only the factory method call.2
Matching the encoder to the transport
Choose the basic encoder for headers, JSON fields, and controlled binary fields. Choose URL-safe encoding for tokens, query parameters, and filenames because the alphabet avoids + and /. Choose MIME encoding only when another system expects 76-character line wrapping, such as legacy mail attachments. This explicit choice prevents later parsers from rejecting otherwise valid output. Consequently, string encoding requires calling str.getBytes(StandardCharsets.UTF_8) before passing to the encoder. Furthermore, withoutPadding() on any encoder strips = characters, which is required for OAuth PKCE parameters and JWT tokens. Before passing decoded bytes to another layer, name the expected charset and byte length in tests so the encoder choice remains visible during code review.
The explicit factory-method choice also makes the encoding decision reviewable in a single line, so a teammate can see at a glance whether a value is standard, URL-safe, or MIME without tracing through helper methods. That visibility is what keeps the standard-versus-URL-safe mismatch from reaching a token parser that only accepts one alphabet.
Working with files and binary data
File encoding uses Files.readAllBytes(Path.of(path)) to load the file as a byte array, then passes it to Base64.getEncoder().encodeToString(), which returns the complete Base64 string in one call. For small files this approach is simple and reliable, but it requires enough heap memory to hold both the raw bytes and the encoded string simultaneously.
Streaming large files without loading them all
For large files, use Base64.getEncoder().wrap(outputStream); this returns an OutputStream that Base64-encodes any bytes written to it and forwards the encoded bytes to the wrapped stream.2 Building on this, streaming decoding uses Base64.getDecoder().wrap(inputStream), enabling on-the-fly decoding of large payloads without loading the entire Base64 string into memory. The wrap pattern is especially useful when you encode a multi-gigabyte file to a network socket or a temporary file, because the encoder processes each write call in small blocks and never requires the full source content to reside in the JVM heap at once. On Android the wrap pattern is particularly valuable because mobile devices have far less heap memory than servers, and an OutOfMemoryError caused by loading a large media file before encoding will crash the app rather than producing a recoverable exception.
Security and common mistakes
Base64 is encoding, not encryption, so it provides no protection for credentials, API keys, or personally identifiable information that must remain confidential. Never rely on Base64 to hide sensitive values from anyone who can read the encoded string; the encoding exists solely to make binary data safe for text-based protocols and storage formats.
Preventing parser and token failures
The most common Java mistake is using getMimeEncoder() (MIME, with line breaks) when the context expects standard Base64 without newlines, because HTTP headers silently fail with multi-line values that contain embedded CRLF characters. For JWT tokens and OAuth PKCE parameters, always use getUrlEncoder().withoutPadding(): forgetting withoutPadding() leaves = characters that break strict parsers expecting the unpadded Base64url format.34 Before returning encoded values from a service, log only the algorithm and length, never the secret bytes behind the value. A second frequent error is calling getEncoder().encodeToString() on a Java String directly without first calling getBytes(), which uses the platform default charset and produces different output on Windows versus Linux deployments. Always specify StandardCharsets.UTF_8 in the byte conversion step to guarantee consistent encoding across environments.
Spring and Jakarta EE integration patterns
Spring REST controllers that accept Base64-encoded payloads can decode them directly in a @RequestBody handler method that processes the incoming HTTP request and extracts the Base64-encoded field from the JSON body before passing it to the service layer for further processing and business logic. Define a DTO with a String field, then call Base64.getDecoder().decode(dto.getEncodedValue()) inside the service layer. Add a @Pattern(regexp = "^[A-Za-z0-9+/=]+$") validation annotation on the field to reject non-Base64 characters at the model binding layer, avoiding IllegalArgumentException propagation to the error handler.5 This validation step catches malformed input before it reaches the decoder, producing a clear 400 response instead of an unhandled exception that surfaces as a confusing 500 error to the client.
For Jakarta EE applications, register a custom @MessageBodyReader in JAX-RS that transparently decodes Base64-encoded binary request bodies. This pattern suits APIs that accept image or document uploads as Base64 in JSON, decoding the string to an InputStream before passing it to the storage service. The @MessageBodyReader integrates with the JAX-RS resource method dispatch, so the decoding happens before the resource method receives the parameter and the application code works with a plain byte array or InputStream.
Validate decoded length before persistence. A Base64 field that looks short in JSON can still expand into a large byte array, and Java decoders allocate that array before your validation code sees it. Set an explicit maximum and reject oversized requests before the binary payload reaches database or filesystem code, because a malicious client can craft a Base64 string that decodes to a multi-gigabyte byte array designed to exhaust server memory. This defense-in-depth approach pairs the regex validation on the input against the maximum decoded length on the output, so neither check alone becomes the sole guard against a crafted payload.
Testing Base64 encoding round-trips in JUnit
Testing Base64 encoding in Java requires verifying both the encoded output and the round-trip decoded result. Use JUnit 5 parameterized tests with @ValueSource to cover edge cases: empty input, single-byte input, two-byte input, and inputs at exactly 3, 6, and 9 bytes to exercise each padding variant. Confirm the encoded string contains only valid characters using assertTrue(encoded.matches("[A-Za-z0-9+/=]+")), which catches any unexpected characters that might corrupt downstream decoders.
For URL-safe encoding tests, verify that no + or / characters appear in the output and that the decoded bytes match the original input byte-for-byte. Use assertArrayEquals(originalBytes, decodedBytes) rather than assertEquals on String values; String comparison can silently skip null bytes present in arbitrary binary data, leading to false-positive test passes that mask real encoding bugs.
When to use this
Use Base64.getEncoder() for standard encoding in Java applications. Use getUrlEncoder().withoutPadding() for JWT, OAuth PKCE, and URL parameters. Use getMimeEncoder() only for MIME email attachments that require 76-character line wrapping.
Notes
Use Base64.getEncoder() for standard Base64, Base64.getUrlEncoder() for URL-safe (replaces +/ with -_), and Base64.getMimeEncoder() for MIME-compliant output (76-character line wrapping). All encoders work with byte[] input. For strings, call str.getBytes(StandardCharsets.UTF_8) first.
Examples
Encode a string
import java.util.Base64;
String encoded = Base64.getEncoder()
.encodeToString("Hello, World!".getBytes());
System.out.println(encoded);
// SGVsbG8sIFdvcmxkIQ== Decode a string
byte[] decoded = Base64.getDecoder().decode("SGVsbG8sIFdvcmxkIQ==");
System.out.println(new String(decoded));
// Hello, World! URL-safe encoding
String encoded = Base64.getUrlEncoder()
.encodeToString("user+name/email".getBytes());
// dXNlcituYW1lL2VtYWls No + or / characters in output.
Encode a file
byte[] fileBytes = Files.readAllBytes(Path.of("image.png"));
String encoded = Base64.getEncoder().encodeToString(fileBytes); Verify with the Base64 Text & File Encoder/Decoder tool.
Encode a string
import java.util.Base64;
String encoded = Base64.getEncoder()
.encodeToString("Hello, World!".getBytes());
System.out.println(encoded);
// SGVsbG8sIFdvcmxkIQ== Code says: SGVsbG8sIFdvcmxkIQ==
- 1.
Oracle, "Base64 (Java SE 23 & JDK 23)," docs.oracle.com, accessed June 2026. https://docs.oracle.com/en/java/javase/23/docs/api/java.base/java/util/Base64.html
- 2.
Oracle, "Base64.Encoder (Java SE 23 & JDK 23)," docs.oracle.com, accessed June 2026. https://docs.oracle.com/en/java/javase/23/docs/api/java.base/java/util/Base64.Encoder.html
- 3.
N. Sakimura, J. Bradley, and N. Agarwal, "Proof Key for Code Exchange by OAuth Public Clients," RFC 7636, IETF, September 2015. https://www.rfc-editor.org/rfc/rfc7636
- 4.
M. Jones, J. Bradley, and N. Sakimura, "JSON Web Token (JWT)," RFC 7519, IETF, May 2015. https://www.rfc-editor.org/rfc/rfc7519
- 5.
"Base64," Wikipedia, accessed June 2026. https://en.wikipedia.org/wiki/Base64
Java 8 and later. For Java 7 and earlier, use javax.xml.bind.DatatypeConverter.printBase64Binary() or Apache Commons Codec.
The basic encoder does not. The MIME encoder wraps at 76 characters with CRLF. Use withoutPadding() on any encoder to omit the = padding characters.
Use Base64.getEncoder().wrap(outputStream) to stream the encoding. This avoids loading the entire file into memory and writes Base64 output directly to a file or network stream. CapyToolkit runs all operations locally in your browser.
No. Base64 is encoding. For encryption, use javax.crypto.Cipher with AES or ChaCha20.
Use getUrlEncoder().withoutPadding() for JWT header and payload segments because JWTs require Base64url without = padding. Decode with the matching URL-safe decoder, then parse the JSON claims. CapyToolkit keeps this same variant distinction visible in its browser-based checks.
Base64 Encode and Decode in Bash
In Bash, Base64 is usually a pipe between commands rather than a standalone library.1
It reads from stdin or a file, writes Base64 to stdout, and requires no package installation for most shell scripts. On Linux, GNU coreutils uses -d for decode, -w 0 to disable its 76-character default wrapping, and -i to ignore non-alphabet bytes while decoding.1 macOS/BSD uses -D for decode, -i input_file for file input, and -b count for wrapping, with default count 0 for an unbroken stream.2 That difference is why cross-platform Bash scripts often strip newlines explicitly with tr -d '\n' instead of relying on one platform's flags. POSIX describes the underlying MIME Base64 algorithm through uuencode -m: 24-bit input groups become four encoded characters, with = padding when fewer than 24 bits remain.3
Core API and encoding variants
The base64 command on Linux (GNU coreutils) and macOS (BSD) behaves differently in one critical way: the -w flag controls line wrapping on Linux, while macOS also accepts -w or the long wrap flag for GNU compatibility but defaults to no wrapping. Start by deciding whether your script runs on one platform or must survive both, because that choice determines whether you normalize wrapping or rely on platform-specific flags. The GNU coreutils version wraps at 76 characters by default, which silently breaks any context that expects a single unbroken Base64 string.
Making shell output portable
Consequently, cross-platform Bash scripts should use base64 | tr -d '
' to strip wrapping on any platform. The decode flag differs as well: -d is the Linux spelling, -D is the portable BSD spelling, and modern macOS also accepts base64 -d.2 Testing your script on both GNU and BSD systems before deploying to CI prevents the subtle wrapping mismatch that produces headers and tokens rejected by strict parsers expecting single-line input.
Stripping the wrapping once at the end of the pipeline is cheaper than fighting per-platform flags, and it guarantees the value that lands in the variable or header is a single continuous string rather than one that a downstream parser will reject. It also keeps your encode and decode logic symmetric, so the same string that leaves one command is the one a later command receives, which removes a whole class of intermittent test failures that only appear on one operating system.
Working with files and binary data
Encoding a file to a Base64 string: base64 image.png or base64 -w 0 image.png > image.b64 on Linux. On macOS/BSD, use base64 -i image.png -o image.b64 or base64 -b 0 -i image.png -o image.b64. Decoding a Base64 file back to binary: base64 -d image.b64 > image.png on Linux, or base64 -D -i image.b64 -o image.png on macOS/BSD.
In a pipeline, pipe binary file content from stdin: cat image.png | base64 -w 0 on Linux. For large files, the base64 command reads stdin and writes stdout, so it can run in a pipeline without a temporary file. OpenSSL provides a cross-platform alternative when the same flags are available in your runner image: openssl enc -base64 -in file -out file.b64 encodes a file, and openssl enc -base64 -d -in file.b64 -out file.bin decodes it.4
Security and common mistakes
Base64 is encoding, not encryption: it represents arbitrary octets as text, but it does not hide the bytes from anyone who can run decode.3 Bash scripts that Base64-encode secrets for environment variables or CI/CD pipelines are not protecting those secrets; OWASP recommends centralizing, standardizing, and controlling access to secrets because readable secrets can leak through people and systems that touch them.5
Keeping shell bytes exact
The most common mistake is using echo 'text' | base64 instead of printf '%s' 'text' | base64: echo normally writes a trailing newline, while printf lets you control the exact bytes sent to Base64.6 This matters for credentials, API keys, and any value that must match exactly. Verify with a round trip such as printf '%s' 'value' | base64 | base64 -d and compare the result to the original string.
OpenSSL as a portable cross-platform alternative
If you need consistent Base64 output on Linux, macOS, and Windows via Git Bash, openssl enc -base64 uses the same Base64 flags without the GNU/BSD flag differences of the base64 command. Encode a file: openssl enc -base64 -in file.bin -out file.b64. Decode: openssl enc -base64 -d -in file.b64 -out file.bin. The -A flag on openssl enc disables the 64-character line wrapping and produces single-line output, equivalent to base64 -w 0 on Linux when OpenSSL is available on the runner.4
For credential encoding in shell scripts where line wrapping is the main concern, printf '%s' 'user:password' | openssl enc -base64 -A produces a clean single-line result when the runner has the same OpenSSL version installed. This approach avoids the GNU/BSD flag differences entirely. ### When to prefer OpenSSL over the base64 command
Keep the fallback narrow: use it for line wrapping and portability, not as a substitute for a secrets manager. OpenSSL is the better choice when your CI pipeline runs on both Linux and Windows build agents, because the openssl enc flags are identical across platforms while the base64 command differs between GNU coreutils and BSD.
Base64 in multi-step shell pipelines
Chaining Base64 encoding into a longer pipeline is straightforward because the base64 command reads from stdin and writes to stdout. You can encode the output of any command and pass it forward without intermediate files: curl -s https://api.example.com/cert | base64 -w 0 | xargs -I{} kubectl create secret generic api-cert && kubectl set data api-cert cert={}. Breaking this down: curl fetches binary content, base64 -w 0 encodes it to a single line, and xargs passes it as a named argument to kubectl.
Assigning encoded values to variables safely
For Base64 values your script will reference multiple times, assign the encoded result to a variable: TOKEN=$(printf '%s:%s' "$USER" "$PASS" | base64 -w 0). Command substitution captures the encoded stdout into the variable instead of writing an intermediate file. Keep the variable scope as narrow as your script allows, and avoid storing long-lived secrets in shell history or logs. Unsetting the variable with unset TOKEN after the last use removes it from the shell's memory, which limits the window during which another process running under the same user could inspect the environment.
When to use this
Use the base64 command for quick string encoding in shell scripts, encoding files for environment variables, and building HTTP Basic Auth headers in curl commands. Use printf '%s' to avoid trailing newlines, and use tr -d '\n' for cross-platform single-line output.
Notes
Encode with base64 <file> or printf "%s" "text" | base64. Decode with base64 -d <file> or echo "SGVsbG8=" | base64 -d. The -w 0 flag disables line wrapping (76-character default on Linux). On macOS/BSD, use -i
Examples
Encode a string
printf "%s" "Hello, World!" | base64 # SGVsbG8sIFdvcmxkIQ==
Use printf to avoid encoding a trailing newline.
Decode a string
echo "SGVsbG8sIFdvcmxkIQ==" | base64 -d # Hello, World!
Encode a file
base64 image.png > image.b64
Decode a file
base64 -d image.b64 > image.png
No line wrapping
base64 -w 0 image.png > image.b64
Linux GNU base64. For macOS/BSD, use -b 0 or tr -d "\n".
Verify with the Base64 Text & File Encoder/Decoder tool.
Encode a string
printf "%s" "Hello, World!" | base64 # SGVsbG8sIFdvcmxkIQ==
Use printf to avoid encoding a trailing newline.
Code says: SGVsbG8sIFdvcmxkIQ==
- 1.
Michael Kerrisk, "base64(1) - Linux manual page," man7.org, April 2026. https://man7.org/linux/man-pages/man1/base64.1.html
- 2.
Apple, "bintrans(1)," keith.github.io, April 2022. https://keith.github.io/xcode-man-pages/bintrans.1
- 3.
The Open Group, "uuencode," pubs.opengroup.org, 2024. https://pubs.opengroup.org/onlinepubs/9799919799/utilities/uuencode.html
- 4.
OpenSSL Project, "openssl-enc," docs.openssl.org, accessed June 2026. https://docs.openssl.org/3.5/man1/openssl-enc/
- 5.
OWASP Foundation, "Secrets Management Cheat Sheet," cheatsheetseries.owasp.org, accessed June 2026. https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html
- 6.
Michael Kerrisk, "echo(1) - Linux manual page," man7.org, April 2026. https://www.man7.org/linux/man-pages/man1/echo.1.html
The Linux base64 command wraps output at 76 characters by default. Use base64 -w 0 to disable wrapping. macOS/BSD defaults to no wrapping, and portable scripts can also remove newlines with tr -d "\n".
echo adds a newline by default. printf "%s" "Hello" sends just "Hello", while echo "Hello" sends "Hello\n", so the newline becomes part of the Base64 output.
Yes. The base64 command is commonly used to encode files, certificates, and configuration values for environment variables. Treat those values as readable secrets, not protected secrets.
No. Base64 is trivially reversible. Use a secrets manager, sealed secret, or encrypted vault for actual protection, then use Base64 only when a tool requires text-safe bytes.
Use printf instead of echo, then strip or prevent wrapping with base64 -w 0 on Linux or tr -d '\n' in portable scripts. CapyToolkit applies the same local-only rule for browser checks: it does not upload pasted values.
Base64 Encode and Decode in Go
Go keeps Base64 choices close to the type you pass.
It provides four encoding variants: StdEncoding, URLEncoding, RawStdEncoding, and RawURLEncoding. The standard and URL-safe alphabets follow RFC 4648, which defines padding behavior and base64url output without line breaks.1
Core API and encoding variants
Go's encoding/base64 package exposes four encoding constants: StdEncoding (standard with padding), URLEncoding (URL-safe with padding), RawStdEncoding (standard without padding), and RawURLEncoding (URL-safe without padding). All four implement the Encoding type with identical method signatures, so switching between variants requires changing only the constant name at the call site.2
Selecting a Go encoding constant
EncodeToString() accepts a []byte and returns a string; DecodeString() takes a string and returns ([]byte, error), reporting malformed input as CorruptInputError. Choose StdEncoding for generic text-safe bytes, URLEncoding for URL-safe values with padding, RawStdEncoding for standard no-padding contexts, and RawURLEncoding for compact URL-safe tokens. Always check the error from DecodeString before using decoded bytes. In handlers, return a 400 response when DecodeString reports CorruptInputError; this keeps malformed input from reaching parsers that interpret binary content. Storing the chosen encoding in a package-level variable means every call site in your service uses the same alphabet, which prevents the subtle bug where one handler encodes with StdEncoding while another decodes with URLEncoding.
Keeping the encoding in a single package-level variable also makes the choice auditable during code review, because a reviewer can confirm every handler uses the same alphabet without searching the whole service. It also means a future change to the alphabet happens in exactly one place, so you cannot accidentally ship a half-migrated service where some endpoints still speak the old encoding.
Working with files and binary data
Encoding a file in Go requires reading it first: content, _ := os.ReadFile(path); encoded := base64.StdEncoding.EncodeToString(content). This approach works well for small files, but it loads the entire file content into memory before encoding begins, which can cause out-of-memory errors on constrained environments like containers with tight memory limits or serverless functions.
Streaming files through encoders and decoders
For large files, the streaming encoder (base64.NewEncoder(base64.StdEncoding, writer)) writes directly to an io.Writer without loading the full file into memory. Always call encoder.Close() after writing because it flushes any partially written blocks and final padding bytes. Conversely, base64.NewDecoder(base64.StdEncoding, reader) streams decoding from any io.Reader, enabling on-the-fly Base64 decoding of HTTP response bodies or file streams.2 This pattern shines when you chain the decoder directly into an io.Copy pipeline, because the data flows from the source reader through the Base64 decoder and into the destination writer without ever allocating a buffer large enough to hold the entire encoded payload. In a microservice that proxies large file uploads, the streaming approach lets you enforce a size limit by counting bytes during the copy and aborting the transfer before the full payload reaches your service memory.
Security and common mistakes
Base64 is encoding, not encryption, which means it provides no confidentiality for sensitive data and should never be marked as safe to log or transmit without an encryption layer. OWASP recommends transmitting secrets only over TLS and controlling access to secret stores through proper authentication and authorization mechanisms.3
Closing streams and matching token formats
The most common Go mistake is forgetting to close the streaming encoder: encoder.Close() flushes the final buffered bytes and padding. Without it, the final partial block is not flushed, which can truncate encoded output and produce strings that fail to decode back to the original bytes. For JWT compact serialization, RFC 7515 uses base64url without padding in URL-safe strings, so RawURLEncoding matches that format better than padded URLEncoding.4 Treat the decoded bytes as untrusted until your handler validates size, type, and ownership. A second common mistake is ignoring the error return from DecodeString entirely. An attacker who controls the Base64 input can send a string that decodes to zero valid bytes without triggering an error, so always check both the error and the decoded length before passing the result to downstream code that interprets binary content.
Base64 in HTTP handlers and middleware
Go HTTP handlers that receive Base64-encoded request bodies decode them inline using base64.StdEncoding.DecodeString() or the URL-safe equivalent depending on the expected encoding format specified by the API contract between the client and server, which should be documented in the API specification. For JSON APIs, parse the JSON body first, extract the Base64 string field, then decode: decoded, err := base64.StdEncoding.DecodeString(req.Base64Field). Always check err before using decoded; an empty error with zero-length bytes indicates a valid empty string, not a decode failure.
HTTP middleware can decode Base64 Authorization headers before passing to the handler: value := r.Header.Get("Authorization"); parts := strings.SplitN(value, " ", 2); credentials, err := base64.StdEncoding.DecodeString(parts[1]). This pattern centralises Basic Auth decoding in one middleware function, keeping handler code focused on business logic rather than header parsing. Returning a 401 response with a WWW-Authenticate header from the middleware short-circuits the request before it reaches any handler logic that assumes a valid principal is present.
Testing Base64 with table-driven tests in Go
Testing Base64 encoding in Go uses the table-driven test pattern common in Go projects. The Go Wiki describes table-driven tests as tables where each entry is a complete test case with inputs and expected results, then the test iterates through those entries.5 Define a slice of structs with input []byte, expected string, and enc *base64.Encoding fields. Iterate with t.Run() and name each case descriptively: "empty input", "single byte", "two bytes", "three bytes full block", "url-safe no padding".
A round-trip test confirms that for any input, encoding followed by decoding returns the original bytes: use bytes.Equal(original, decoded) rather than string comparison for binary correctness. Add fuzzing with go test -fuzz to let the Go fuzzer generate edge cases that the fixed table cannot anticipate; the official Go fuzzing tutorial shows go test -fuzz=Fuzz and -fuzztime to limit the run.6
When to use this
Use base64.StdEncoding for standard encoding in Go applications such as HTTP Basic Auth, data URIs, and binary JSON fields. Use base64.RawURLEncoding for JWT compact serialization and URL parameters because RFC 7515 defines base64url without padding for compact, URL-safe representations.4 Use base64.NewEncoder for streaming encoding of large files.
Notes
Use base64.StdEncoding for standard Base64 and base64.URLEncoding for URL-safe. Add Raw prefix (RawStdEncoding, RawURLEncoding) to omit padding. For streaming, use base64.NewEncoder(enc, writer) which implements io.WriteCloser. Always close the encoder to flush remaining bytes.
Examples
Encode a string
import "encoding/base64"
encoded := base64.`StdEncoding`.EncodeToString(
[]byte("Hello, World!"),
)
fmt.Println(encoded)
// SGVsbG8sIFdvcmxkIQ== Decode a string
decoded, _ := base64.`StdEncoding`.`DecodeString`(
"SGVsbG8sIFdvcmxkIQ==",
)
fmt.Println(string(decoded))
// Hello, World! URL-safe without padding
encoded := base64.`RawURLEncoding`.EncodeToString(
[]byte("user+name"),
)
// dXNlcituYW1l No +, /, or = characters.
Stream encode a file
file, _ := os.Open("image.png")
defer file.Close()
out, _ := os.Create("image.b64")
defer out.Close()
encoder := base64.`NewEncoder`(base64.`StdEncoding`, out)
defer `encoder.Close()`
io.Copy(encoder, file) Verify with the Base64 Text & File Encoder/Decoder tool.
Encode a string
import "encoding/base64"
encoded := base64.`StdEncoding`.EncodeToString(
[]byte("Hello, World!"),
)
fmt.Println(encoded)
// SGVsbG8sIFdvcmxkIQ== Code says: SGVsbG8sIFdvcmxkIQ==
- 1.
S. Josefsson, "RFC 4648: The Base16, Base32, and Base64 Data Encodings," rfc-editor.org, October 2006. https://www.rfc-editor.org/rfc/rfc4648
- 2.
Go Project, "Package base64," pkg.go.dev, accessed June 2026. https://pkg.go.dev/encoding/base64
- 3.
OWASP Foundation, "Secrets Management Cheat Sheet," cheatsheetseries.owasp.org, accessed June 2026. https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html
- 4.
M. Jones, J. Bradley, and N. Sakimura, "RFC 7515: JSON Web Signature (JWS)," rfc-editor.org, May 2015. https://www.rfc-editor.org/rfc/rfc7515
- 5.
Go Project, "Go Wiki: TableDrivenTests," go.dev, accessed June 2026. https://go.dev/wiki/TableDrivenTests
- 6.
Go Project, "Tutorial: Getting started with fuzzing," go.dev, accessed June 2026. https://go.dev/doc/tutorial/fuzz
StdEncoding adds = padding to the output. RawStdEncoding omits padding. JWT payloads and URL parameters often use raw (unpadded) encoding to avoid characters that need escaping.
Yes. The streaming encoder buffers data and writes in blocks. Calling Close() flushes any remaining buffered bytes. Without it, the last few bytes of output may be missing.
Read the body with io.ReadAll(r.Body), then decode with base64.StdEncoding.DecodeString(). For large payloads, use base64.NewDecoder() wrapping the response body for streaming decode. CapyToolkit gives Go developers a local check for small samples, so you can compare encoded values without sending test data anywhere.
Yes. encoding/base64 is part of the standard library, so you do not need third-party dependencies.
Use RawURLEncoding for JWT header and payload segments because JWT compact serialization uses Base64url without padding. Decode with the matching URL-safe decoder and parse the JSON after validation. CapyToolkit keeps standard and URL-safe variants separate for the same reason.
Base64 Encode and Decode in TypeScript
When a TypeScript codebase carries Base64 values, the type system can show where encoding boundaries happen.
It uses the same runtime functions as JavaScript. On Node.js, that means Buffer.from().1 On Deno, the standard library exports encodeBase64() and decodeBase64().2 In browsers, btoa() and atob() handle binary strings, while the TextEncoder pattern extends coverage to Unicode.3 The practical difference from JavaScript is type safety: typing these correctly prevents the common bug of passing an unencoded string where a Base64-encoded one is expected.
Core API and encoding variants
In Node.js TypeScript, Buffer.from(str).toString('base64') encodes any string regardless of character set, and Buffer.from(b64, 'base64').toString('utf-8') decodes it back to the original text. Keep the helper signature narrow so a plain string cannot silently enter a decode function, because the type system is your first defense against encoding mix-ups that cause silent data corruption.
Keeping runtime APIs typed
Both methods handle UTF-8 Unicode without the Latin-1 restriction of btoa(). In Deno, import { encodeBase64, decodeBase64 } from '@std/encoding/base64' for standard encoding; '@std/encoding' also exports URL-safe base64url helpers.2 Consequently, TypeScript code that targets both Node.js and Deno should abstract the encoding behind a utility function typed as (data: Uint8Array) => string. Picking one runtime path and typing it precisely prevents the common bug where a developer accidentally passes raw UTF-8 text to a function that expects Base64-encoded input, which produces silent data corruption that is difficult to trace without explicit type boundaries.
Narrowing the helper signature also documents the encoding boundary for future maintainers, because the type itself states that only already-encoded bytes may enter the decode path. It also turns a class of silent corruption bugs into compile-time errors, so a refactor that reorders how bytes travel through the service cannot accidentally introduce an encoding mismatch that only surfaces in production.
Working with files and binary data
Node.js file encoding is straightforward: fs.readFileSync(path) returns a Buffer, and Buffer.prototype.toString('base64') encodes it in one step without any character-set conversion issues. For Deno, Deno.readFile() returns a Uint8Array, which encodeBase64() accepts directly. In browsers, File.arrayBuffer() returns an ArrayBuffer containing the file's binary data, which can be wrapped as a Uint8Array before encoding.4 Furthermore, streaming large files in Node.js uses the Transform stream class; Transform streams can modify data as it is written and read, and streams commonly operate on Buffer/TypedArray chunks.5 When you target all three runtimes from a single TypeScript codebase, abstract the encoding behind a small utility function that narrows the input type to Uint8Array and returns a string, then implement each runtime path behind a conditional import or a platform detection check at module initialization time.
Security and common mistakes
TypeScript's type system does not distinguish between a Base64 string and a plain string at the value level. Using a branded type (type Base64String = string & { _brand: 'Base64' }) helps separate encoded values from raw text at compile time. Base64 is not encryption , never mark a field as 'safe to log' because it is Base64-encoded.
Validating encoded values at boundaries
Furthermore, the browser btoa() function throws on non-Latin-1 characters even in TypeScript; use Buffer.from or the TextEncoder workaround rather than btoa() directly.3 On Node.js, Buffer.from(str, 'base64') assumes valid input, so validate untrusted Base64 before decoding.1 A simple regular expression check such as /^[A-Za-z0-9+/=]+$/ catches most malformed strings before they reach the decoder, and adding a length ceiling prevents oversized payloads from consuming excessive memory during the decode step.
Branded types for compile-time encoding safety
If your codebase passes Base64 strings and plain strings through the same function signatures, a branded type catches encoding mistakes at compile time rather than at runtime. Define type Base64String = string & { readonly _brand: 'Base64' } and use it as the return type of your encoding functions. TypeScript's structural type system treats Base64String as assignable to string everywhere, but it prevents assigning a plain string to a Base64String parameter without an explicit cast.6
The practical benefit is catching the common bug of passing an unencoded value to a function that calls Buffer.from(input, 'base64'). Any call site that feeds a plain string into a function typed as (encoded: Base64String) => Uint8Array produces a type error at compile time. You write the brand cast exactly once at the encoding boundary, and the type system enforces correctness through the rest of the call chain with no runtime overhead.
Base64 encoding in the browser File API
In browser TypeScript, encoding a file for a JSON API upload uses File.arrayBuffer() combined with a Uint8Array to bridge the gap between the File API and btoa(). The pattern: const buf = await file.arrayBuffer(); const bytes = new Uint8Array(buf); const b64 = btoa(String.fromCharCode(...bytes)); works for files up to a few megabytes before hitting engine limits. This two-step conversion is necessary because btoa() only accepts a binary string, not a typed array, so the bytes must be joined into a string before encoding.
Avoiding stack overflow on large files
For files over one megabyte, String.fromCharCode(...bytes) throws a stack overflow because the spread operator hits the JavaScript engine's maximum argument count limit, which varies by browser but is typically around 65536. Replace the spread with a chunked loop that processes the Uint8Array in manageable pieces: let binary = ''; const chunk = 1024; for (let i = 0; i < bytes.length; i += chunk) { binary += String.fromCharCode(...bytes.subarray(i, i + chunk)); }. This approach processes 1,024 bytes at a time and avoids the argument count limit. In Node.js TypeScript, Buffer.from(await readFile(path)).toString('base64') handles any file size cleanly without this limitation.
When to use this
Use Buffer.from() in Node.js TypeScript for all Base64 encoding , it handles Unicode, binary files, and streams. Use Deno standard library functions in Deno projects. Use the TextEncoder pattern only in browser-only code where btoa() falls short.
Notes
Node.js: Buffer.from(str).toString('base64') to encode, Buffer.from(b64, 'base64').toString('utf-8') to decode. Deno: import { encodeBase64, decodeBase64 } from '@std/encoding/base64'. Browser: TextEncoder + btoa() for Unicode. No external packages needed on any platform.
Examples
Node.js: encode
const encoded = Buffer.from('Hello, World!').toString('base64');
console.log(encoded);
// SGVsbG8sIFdvcmxkIQ== Node.js: decode
const decoded = Buffer.from('SGVsbG8sIFdvcmxkIQ==', 'base64').toString('utf-8');
console.log(decoded);
// Hello, World! Deno: encode and decode
import { encodeBase64, decodeBase64 } from '@std/encoding/base64';
const encoded = encodeBase64(new TextEncoder().encode('Hello, World!'));
const decoded = new TextDecoder().decode(decodeBase64(encoded)); Browser: Unicode encode
function toBase64(str: string): string {
const bytes = new TextEncoder().encode(str);
const binary = String.fromCharCode(...bytes);
return btoa(binary);
} Verify with the Base64 Text & File Encoder/Decoder tool.
Node.js: encode
const encoded = Buffer.from('Hello, World!').toString('base64');
console.log(encoded);
// SGVsbG8sIFdvcmxkIQ== Code says: SGVsbG8sIFdvcmxkIQ==
- 1.
Node.js Foundation, "Buffer," nodejs.org, accessed June 2026. https://nodejs.org/api/buffer.html
- 2.
denoland, "encoding/mod.ts," github.com, accessed June 2026. https://github.com/denoland/std/blob/main/encoding/mod.ts
- 3.
MDN Contributors, "Window: btoa() method," developer.mozilla.org, 2025. https://developer.mozilla.org/en-US/docs/Web/API/Window/btoa
- 4.
World Wide Web Consortium, "File API," w3.org, June 2026. https://www.w3.org/TR/FileAPI/
- 5.
Node.js Foundation, "Stream," nodejs.org, accessed June 2026. https://nodejs.org/api/stream.html
- 6.
Microsoft, "Type Compatibility," github.com, accessed June 2026. https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Type%20Compatibility.md
Use Buffer.from() in Node.js , it handles all character sets natively and is the standard pattern. Use TextEncoder + btoa() in browser TypeScript when you need to encode Unicode strings without a polyfill.
No. TypeScript represents Base64 as a plain string. Use a branded type (type Base64String = string & { __brand: 'base64' }) to distinguish encoded from unencoded strings at compile time.
Deno's standard library provides @std/encoding/base64 (standard) and @std/encoding/base64url (URL-safe). Both export encodeBase64() and decodeBase64() functions that accept Uint8Array and return string.
Yes, as of Node.js 16, btoa() and atob() are global. For binary data, Buffer.from() is still the correct choice because btoa() only accepts Latin-1 strings.
Yes. CapyToolkit is a browser-based Base64 tool, so you can encode or decode sample values before passing them into TypeScript Buffer.from(), Deno decodeBase64(), or your own runtime adapter.
Base64 Encode and Decode in Rust
In Rust, Base64 is an explicit dependency choice.
The standard library documentation does not list a Base64 module in std, so Rust projects commonly use the external base64 crate.1
The base64 crate is widely used and provides an Engine trait that abstracts over alphabet and padding configurations.2 Version 0.21 introduced the engine-based API: base64::engine::general_purpose::STANDARD.encode(data) for standard encoding, STANDARD_NO_PAD for unpadded output, and URL_SAFE / URL_SAFE_NO_PAD for URL-safe variants.3 The older encode() and decode() free functions still compile but are deprecated.
Core API and encoding variants
The base64 crate exports four pre-built engines in base64::engine::general_purpose: STANDARD (with padding), STANDARD_NO_PAD (no padding), URL_SAFE (URL-safe with padding), and URL_SAFE_NO_PAD (URL-safe without padding). Each engine implements the Engine trait with encode() and decode() methods, and the trait accepts any input that implements AsRef<[u8]>. In application code, store the selected engine in one small adapter so callers do not mix standard and URL-safe values across modules.4
Choosing the right Rust engine
Consequently, switching between variants is a single constant change with no API differences. Furthermore, Engine::encode_string() writes into an existing String to avoid allocation, and Engine::decode_vec() writes into an existing Vec<u8> for the same reason. Storing the chosen engine in a module-level constant means every call site in your crate uses the same alphabet and padding configuration, which eliminates the risk of accidentally mixing standard and URL-safe output across different parts of the application.
Holding the engine in one module-level constant also makes the padding decision consistent with the alphabet, so a URL-safe value never accidentally carries standard padding characters. It also keeps the decision in one place for review, so a teammate auditing the crate sees the chosen engine and padding together instead of hunting through scattered call sites.
Working with files and binary data
The base64 crate works with any type that implements AsRef<[u8]>: &[u8], Vec<u8>, String, and file content read with fs::read(). For large files, read the content into a Vec<u8> with std::fs::read(path)? and call engine.encode(&bytes), which returns the complete Base64-encoded string in one call.5 Streaming encoding uses the chunked read pattern: read N bytes (where N is a multiple of 3), encode each chunk with engine.encode(), and concatenate the results into a single output string.6 On memory-constrained services, prefer bounded reads and explicit maximum sizes so an unexpected upload cannot force a large allocation before validation. In an async Rust service using tokio, you can offload the encoding work to a blocking task with tokio::task::spawn_blocking, which prevents the Base64 computation from starving the async runtime and keeps other requests responsive while a large file is being encoded.
Security and common mistakes
Base64 is encoding, not encryption, which means it provides no protection for sensitive data including passwords, API keys, or certificates that must remain confidential.7 Never store secrets in Base64-encoded strings and assume they are protected from anyone who can read the encoded value; treat them as plaintext that anyone can decode instantly.
Handling decode errors explicitly
The most common mistake in Rust is calling engine.decode() without validating the length; DecodeError::InvalidLength reports an invalid number of valid Base64 symbols.8 Always match your unwrap() with proper error handling: engine.decode(input).map_err(|e| Error::InvalidBase64(e)). Furthermore, the pre-0.21 API used a Config struct; code using the old decode_config() or encode_config() API still compiles but produces deprecation warnings. Migrate to the engine-based API before it is removed. When you propagate decode errors with the ? operator instead of panicking, the caller can decide whether to return a 400 status to the client or retry the operation, which keeps the decoding layer focused on parsing and leaves policy decisions to the HTTP handler.
Error handling and the DecodeError type
Decoding untrusted Base64 input in Rust requires matching every error case from the DecodeError enum.8 The variants include InvalidByte (a character outside the Base64 alphabet), InvalidLength (an invalid number of valid Base64 symbols), InvalidLastSymbol (a symbol in the alphabet with nonsensical trailing bits), and InvalidPadding (padding that does not match the configured mode). Each variant carries enough context to build a meaningful error message for the caller.
For applications that accept Base64 from external sources, the correct pattern wraps engine.decode() in a Result chain rather than calling unwrap(): let bytes = general_purpose::STANDARD.decode(input).map_err(|e| MyError::Base64(e))?;. Propagating the error with ? keeps the call site clean while giving callers the ability to handle corrupt or attacker-controlled input appropriately. Never call unwrap() on decode output when the source is untrusted.
Using the base64 crate in no-std environments
In no-std environments, the base64 crate compiles with default-features = false in Cargo.toml. Without the std feature, the crate requires the alloc crate for String and Vec<u8> output, but it otherwise runs on bare-metal targets without an operating system.2 Add base64 = { version = "0.22", default-features = false, features = ["alloc"] } to enable string encoding on embedded systems.
Allocation-free encoding for tight memory budgets
The Engine::encode_slice() method writes encoded bytes into a caller-provided &mut [u8] buffer with no heap allocation.4 For microcontrollers and memory-constrained targets, this is the correct method: pre-allocate a buffer of size (input.len() + 2) / 3 * 4 and call encode_slice with it.6 If the provided buffer is too small, the method returns EncodeSliceError::OutputSliceTooSmall rather than panicking.3 Validate the buffer size calculation before encoding to avoid this error in interrupt handlers or hard-real-time contexts. On a microcontroller with only 64 KB of RAM, knowing the exact output buffer size in advance lets you encode sensor data or cryptographic signatures without touching the heap at all, which is the difference between a firmware image that fits and one that overflows the available memory.
When to use this
Use the base64 crate for any Rust code that needs to encode or decode Base64 , web servers serializing binary fields in JSON, CLI tools processing PEM files, and cryptographic libraries packaging keys. Add base64 = "0.22" to Cargo.toml.
Notes
Add base64 = "0.22" to Cargo.toml. Import: use base64::{Engine, engine::general_purpose}. Encode: general_purpose::STANDARD.encode(bytes). Decode: general_purpose::STANDARD.decode(s)?. Use URL_SAFE_NO_PAD for JWTs. Migrate from pre-0.21 API: replace encode_config/decode_config with the engine API.
Examples
Encode bytes
use base64::{Engine, engine::general_purpose};
let encoded = general_purpose::STANDARD.encode(b"Hello, World!");
println!("{}", encoded);
// SGVsbG8sIFdvcmxkIQ== Decode a string
use base64::{Engine, engine::general_purpose};
let decoded = general_purpose::STANDARD.decode("SGVsbG8sIFdvcmxkIQ==")?;
println!("{}", String::from_utf8(decoded)?);
// Hello, World! URL-safe without padding
use base64::{Engine, engine::general_purpose};
let encoded = general_purpose::URL_SAFE_NO_PAD.encode(b"user+name/data");
// No +, /, or = characters Encode a file
use base64::{Engine, engine::general_purpose};
use std::fs;
let bytes = fs::read("image.png")?;
let encoded = general_purpose::STANDARD.encode(&bytes);
println!("{} chars", encoded.len()); Verify with the Base64 Text & File Encoder/Decoder tool.
Encode bytes
use base64::{Engine, engine::general_purpose};
let encoded = general_purpose::STANDARD.encode(b"Hello, World!");
println!("{}", encoded);
// SGVsbG8sIFdvcmxkIQ== Code says: SGVsbG8sIFdvcmxkIQ==
- 1.
The Rust Project, "std," doc.rust-lang.org, accessed June 2026. https://doc.rust-lang.org/stable/std/index.html
- 2.
Marshall Pierce, "rust-base64," github.com, accessed June 2026. https://github.com/marshallpierce/rust-base64/blob/master/README.md
- 3.
Marshall Pierce, "RELEASE-NOTES.md," github.com, accessed June 2026. https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md
- 4.
Marshall Pierce, "Engine in base64::engine," docs.rs, accessed June 2026. https://docs.rs/base64/0.21.7/base64/engine/trait.Engine.html
- 5.
The Rust Project, "read in std::fs," doc.rust-lang.org, accessed June 2026. https://doc.rust-lang.org/stable/std/fs/fn.read.html
- 6.
Simon Josefsson, "The Base16, Base32, and Base64 Data Encodings," RFC 4648, IETF, October 2006. https://datatracker.ietf.org/doc/html/rfc4648
- 7.
OWASP Foundation, "Encoded Injection," owasp.org, accessed June 2026. https://owasp.org/www-project-web-security-testing-guide/latest/6-Appendix/D-Encoded_Injection
- 8.
Marshall Pierce, "DecodeError in base64," docs.rs, accessed June 2026. https://docs.rs/base64/0.21.7/base64/enum.DecodeError.html
Use a current 0.22.x release. The engine-based API was introduced in 0.21. Versions before 0.21 use the older encode_config/decode_config API which is deprecated.
STANDARD appends = padding characters to align the output to a multiple of 4 characters. STANDARD_NO_PAD omits padding. JWT tokens require no padding; PEM files and MIME encoding require padding.
engine.decode() returns Result<Vec<u8>, DecodeError>. The error variants include InvalidByte (non-base64 character), InvalidLength, InvalidLastSymbol (invalid trailing bits), and InvalidPadding. Use ? to propagate or match for custom handling.
Yes. Add base64 = { version = "0.22", default-features = false } to Cargo.toml. The engine API works in no-std with alloc.
Yes. Encode your test data in the CapyToolkit Base64 encoder, then compare against Rust output. All operations run locally , no data is sent to any server.
Base64 Encode and Decode in PHP
PHP turns binary bytes into text-safe strings for protocols that expect characters, not for secrecy.12
It includes base64_encode() and base64_decode() as built-in functions, with no extension or package required. Both functions work with standard Base64, including +, /, and = padding, which suits HTTP Basic Auth, data URIs, and MIME email.3 For URL-safe Base64, PHP has no built-in urlsafe variant; use strtr() to substitute characters after encoding. JWT libraries like firebase/php-jwt handle the conversion internally. Keep the helper name explicit so future maintainers know the alphabet before they paste the value into a URL.
Core API and encoding variants
base64_encode(string $string): string accepts any string and returns the Base64-encoded result with = padding, and it requires no extension or package installation since it is a built-in function available in every PHP installation.1 base64_decode(string $string, bool $strict = false): string|false decodes and returns the binary string or false on failure when the input contains characters outside the valid Base64 alphabet.2
Choosing strict decoding and URL-safe output
Consequently, always check the return value: if ($decoded === false) { /* handle error */ }. Setting $strict = true makes the decoder reject non-Base64 characters; without it, invalid characters are silently ignored. For URL-safe output, chain with strtr($encoded, '+/', '-_') and rtrim($stripped, '=') after encoding.4 In framework validation, keep that substitution in one named helper so routes, tokens, and tests all agree on the same alphabet. PHP 8's stricter type system helps here: typing the helper parameter as string prevents accidental null or array values from reaching base64_encode and producing unexpected results or deprecation warnings.
Keeping the substitution in a single named helper also means every route, token, and test relies on the same alphabet, so a URL-safe value never accidentally ships with standard characters that a strict parser would reject. It also shortens the diff when you change the alphabet later, because the update lands in one function instead of scattered across controllers and middleware.
Working with files and binary data
Encoding a file requires reading the file bytes first with file_get_contents() or fopen(), then passing those bytes directly to base64_encode(). For small files this is straightforward, but remember that the entire file content must fit in memory before encoding begins, which limits this approach to files smaller than the PHP memory limit.
Handling files without losing binary meaning
For very large files, read in chunks of 3 × N bytes: each multiple-of-3 chunk encodes cleanly to Base64 without padding, allowing chunks to be concatenated into a single valid output. Track the decoded byte limit before the upload reaches storage, because the encoded string can look shorter than the binary payload it represents.3 Furthermore, chunk_split(base64_encode($data), 76, "\r\n") applies MIME-standard line wrapping automatically. This MIME wrapping is required when you embed Base64 content inside email attachments, because many SMTP relays reject lines longer than 76 characters and the email client relies on those line breaks to decode the attachment correctly. On a typical PHP-FPM worker with 128 MB memory limit, loading a 50 MB file for Base64 encoding will exhaust the available memory before the operation completes, so the chunked approach is not optional for large file processing in PHP.
Security and common mistakes
Base64 is encoding, not encryption, so it provides no protection for user data, API keys, or passwords that must remain confidential in your application.5 Never use base64_encode() to protect sensitive values; anyone who intercepts the encoded string can decode it instantly with no key or special knowledge whatsoever, making it equivalent to plaintext.
Validating decoded uploads before trust
The most common mistake is treating false returns from base64_decode() as an empty string, because strict mode ($strict = true) prevents silent corruption of binary data that happens to decode without error from malformed input. For authentication: HTTP Basic Auth requires base64_encode('user:password') with the standard alphabet and no URL-safe substitutions.6 Data URIs require 'data:' . $mime . ';base64,' . base64_encode($content). Neither context strips padding. In PHP 8, prefer explicit string types for helper parameters so accidental arrays or null values fail before encoding. A practical defense-in-depth measure is to validate the decoded byte length against an expected maximum before passing the result to image resizing, PDF parsing, or any library that allocates memory based on the binary content, because a Base64 string that looks short in a request body can still expand into a byte array large enough to trigger a denial-of-service condition.
Laravel and Symfony Base64 integration
In PHP frameworks, keep Base64 encoding and decoding in a service layer or normalizer instead of scattering it through controllers and models. Define one helper for binary property values before serialization and another for incoming decoded data. Keeping the transformation in one place makes it easier to test, audit, and replace if your API changes its encoding requirements. In Laravel, a custom Eloquent cast can transparently Base64-encode a binary attribute on write and decode it on read, so the rest of your application works with raw bytes while the database stores the encoded string. Symfony's Serializer component supports custom normalizers that apply the same pattern: implement NormalizerInterface, check for a BinaryField attribute on each property, and call base64_encode or base64_decode during the normalization and denormalization steps.
When accepting Base64 input from an API request
Validate the format before decoding. Use preg_match('/^[A-Za-z0-9+\/=]+$/', $input) to reject strings that contain non-Base64 characters.4 Follow the pattern check with $decoded = base64_decode($input, true), where the second argument enables strict mode. If $decoded === false, return a 400 Bad Request response with a descriptive message before attempting any further processing.
After decoding, validate the resulting bytes match the expected format before accepting them. Relying solely on the declared Content-Type without verifying the binary content allows arbitrary file uploads disguised as images, which is a common PHP file upload vulnerability. Define an explicit byte limit before decoding, because the decoded binary size determines upload impact. For APIs that accept images or documents, verify magic bytes and dimensions after decoding rather than trusting the field name alone. This validation should happen before database writes, image resizing, or document conversion, because those steps often allocate memory based on the decoded content.
When to use this
Use base64_encode() and base64_decode() for HTTP Basic Auth headers, data URIs, MIME email attachments, and binary data in JSON payloads.6 Use strtr() post-encoding for URL-safe output in custom JWT or OAuth implementations.
Notes
No import needed , base64_encode() and base64_decode() are global built-in functions. For URL-safe: strtr(base64_encode($data), '+/', '-_'). For strict decoding: base64_decode($str, true). Line wrap for MIME: chunk_split(base64_encode($data), 76, "\r\n").
Examples
Encode a string
$encoded = base64_encode('Hello, World!');
echo $encoded;
// SGVsbG8sIFdvcmxkIQ== Decode a string
$decoded = base64_decode('SGVsbG8sIFdvcmxkIQ==');
echo $decoded;
// Hello, World! URL-safe encoding
function base64url_encode(string $data): string {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
function base64url_decode(string $data): string {
return base64_decode(strtr($data, '-_', '+/'));
} Encode a file
$content = file_get_contents('image.png');
$encoded = base64_encode($content);
$dataUri = 'data:image/png;base64,' . $encoded; Verify with the Base64 Text & File Encoder/Decoder tool.
Encode a string
$encoded = base64_encode('Hello, World!');
echo $encoded;
// SGVsbG8sIFdvcmxkIQ== Code says: SGVsbG8sIFdvcmxkIQ==
- 1.
The PHP Group, "base64_encode," php.net, accessed June 2026. https://www.php.net/manual/en/function.base64-encode.php
- 2.
The PHP Group, "base64_decode," php.net, accessed June 2026. https://www.php.net/manual/en/function.base64-decode.php
- 3.
N. Freed and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies," RFC 2045, IETF, November 1996. https://www.rfc-editor.org/rfc/rfc2045
- 4.
S. Josefsson, "The Base16, Base32, and Base64 Data Encodings," RFC 4648, IETF, October 2006. https://datatracker.ietf.org/doc/html/rfc4648
- 5.
OWASP Foundation, "Secrets Management Cheat Sheet," cheatsheetseries.owasp.org, accessed June 2026. https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html
- 6.
J. Reschke, "The 'Basic' HTTP Authentication Scheme," RFC 7617, IETF, September 2015. https://www.rfc-editor.org/rfc/rfc7617
By default yes , PHP adds missing = padding internally before decoding. With $strict = true it validates the padding strictly, which is recommended when decoding external input.
With $strict = false (default), invalid characters are silently ignored. With $strict = true, any invalid character returns false. Always check the return value and use strict mode for untrusted input.
chunk_split(base64_encode($data), 76, "\r\n") wraps the output at 76 characters with CRLF line endings, matching the RFC 2045 requirement for MIME email attachments.
No. PHP has no urlsafe_base64_encode() function. Use strtr(base64_encode($data), '+/', '-_') and rtrim($result, '=') to produce URL-safe output.
Yes. PHP's base64_encode() produces standard Base64 with = padding , the same format the CapyToolkit decoder expects.
Base64 Encode and Decode in C#
In C#, Base64 is a byte-array conversion with a clear allocation cost.1
C# and .NET provide Base64 encoding through the System.Convert class without any additional packages.
Convert.ToBase64String() encodes a byte array to standard Base64; Convert.FromBase64String() decodes it back. .NET 5 and later add System.Buffers.Text.Base64 for high-performance work with Span<byte>.2 For URL-safe Base64, apply the RFC 4648 URL and filename safe alphabet after standard encoding: replace + with -, replace / with _, and remove = padding when the receiver expects an unpadded token.3 Name URL-safe helpers explicitly, because a later reader should not have to infer whether a token is safe inside a URL.
Core API and encoding variants
Convert.ToBase64String(byte[] inArray) returns a standard Base64 string with = padding, and Convert.FromBase64String(string s) decodes it back to a byte[]. Both methods are available through the System.Convert class without any additional using directives in typical .NET projects, making them the simplest starting point for Base64 operations in any C# codebase. The pair mirrors each other symmetrically so encoding and decoding always use the same padding and alphabet rules, which reduces the chance of mismatched variants when different developers write the encode and decode sides of the same feature.
Choosing standard, MIME, or URL-safe output
Pass Base64FormattingOptions.InsertLineBreaks as the second argument to add line breaks every 76 characters for MIME-style output.4 For URL-safe output, chain: Convert.ToBase64String(bytes).Replace('+', '-').Replace('/', '_').TrimEnd('=').3 System.Buffers.Text.Base64.EncodeToUtf8() and DecodeFromUtf8() operate on Span<byte> for allocation-conscious encoding in hot paths.2 The span-based APIs matter most in high-throughput services where every allocation adds garbage collection pressure, because writing directly into a pre-allocated buffer avoids the intermediate string that ToBase64String creates on every call. In a gRPC or SignalR hub that serializes binary payloads as Base64 strings, switching from ToBase64String to EncodeToUtf8 can reduce per-request allocations by the size of the encoded output, which adds up quickly under sustained load.
The symmetric encode and decode pair also means a single helper that wraps both sides keeps the padding and alphabet identical, which is what prevents a value encoded with one method from failing to decode with its counterpart. It also gives you one auditable place to enforce the URL-safe substitution, so the same rule applies whether the value travels in a JWT, a query string, or a stored secret.
Working with files and binary data
File encoding is a two-step operation in C#: File.ReadAllBytes(path) returns a byte[], which Convert.ToBase64String() encodes directly to a Base64 string. This approach works well for small to medium files that fit in memory, but it requires enough RAM to hold both the raw file bytes and the resulting Base64 string simultaneously, which can become a problem once files exceed a few hundred megabytes.
Streaming .NET files through Base64
For streaming large files, read the file in 3 × N byte chunks, encode each chunk, and write to a StreamWriter. RFC 4648 defines Base64 as 3 input octets mapped to 4 output characters, so chunking by multiples of 3 keeps each encoded block aligned without partial-block padding in the middle of the stream. For ASP.NET Core file uploads, IFormFile.OpenReadStream() provides a Stream; read it with MemoryStream, then encode the byte array. For very large binary responses, avoid ToBase64String() on the full byte[] because it creates a large intermediate string. Prefer chunked reads and enforce a maximum decoded length before copying into memory. This keeps upload validation tied to the actual binary size rather than the encoded field length alone.
Security and common mistakes
Convert.FromBase64String() throws FormatException for invalid padding or characters rather than returning null, so always wrap it in try/catch when handling external input from untrusted sources.1 Base64 is not encryption: Convert.ToBase64String(Encoding.UTF8.GetBytes(password)) does not protect the password from anyone who can read the encoded string. Treating Base64 as a security measure is one of the most persistent mistakes in application security, because the encoding is fully reversible by anyone who has access to the encoded value, with no key or secret required to recover the original content.
Choosing validation over assumptions
Store passwords with a slow password hashing algorithm such as Argon2id or bcrypt, with unique salts and conservative work factors that make brute-force attacks computationally expensive.5 For encoded request bodies, validate the expected length before decoding and reject oversized values before they allocate a byte array. Checking the string length against a known maximum before calling FromBase64String is a cheap guard that prevents a malicious client from sending a multi-gigabyte payload designed to exhaust your server memory during the decode step. In ASP.NET Core, the MaxReceivedMessageSize setting on Kestrel provides a first layer of defense, but it applies to the entire request body rather than individual Base64 fields, so field-level validation remains necessary for APIs that accept multiple encoded fields in a single request.
Convert.TryFromBase64String for validation paths
Convert.TryFromBase64String(string s, Span<byte> bytes, out int bytesWritten) is a span-based API for decoding Base64 without relying on exception control flow; it was approved for .NET Core 2.1 and is available in all modern .NET versions.6 Use it when processing Base64 input from untrusted sources such as user uploads, webhook payloads, or public API endpoints.
Pair TryFromBase64String with a pre-allocated Span<byte> buffer sized at least (inputLength / 4) * 3 bytes for valid Base64 input. The bytesWritten out parameter gives the exact decoded byte count, avoiding the need to trim the result. The key advantage over FromBase64String is that TryFromBase64String returns a bool instead of throwing an exception, which means your hot path avoids the cost of exception allocation and stack unwinding on every malformed input. In a high-volume API that processes thousands of Base64-encoded uploads per second, this difference is measurable: exception-based error handling can dominate CPU profiles when even a small percentage of requests contain invalid data.
When an ASP.NET Core controller accepts a Base64 field
Define the model property as string and decode in the service layer rather than in the model binder, because model binders do not know the application's encoding intent. Decoding in the service layer keeps the transformation explicit and independently testable through unit tests. This separation also means the decode logic lives outside the request pipeline, so changes to encoding strategy do not require touching the model binding configuration or restarting the application.
Add a custom [Base64String] validation attribute that overrides IsValid() and calls Convert.TryFromBase64String() to check the field value. Returning a ValidationResult with the message 'value must be valid Base64' produces a 400 response with a descriptive error before the decoding step runs. Register the attribute on string fields in your request DTO to enforce this validation consistently across all endpoints that receive encoded binary data.
When to use this
Use Convert.ToBase64String() for standard Base64 in .NET projects , HTTP Basic Auth headers, data URIs, and binary-in-JSON fields. Use System.Buffers.Text.Base64 for high-performance, allocation-conscious encoding in hot paths. Use RFC 4648 URL-safe Base64 for JWT, OAuth PKCE, and other tokens that must avoid + and /.
Notes
No using needed , System.Convert is in scope by default. Encode: Convert.ToBase64String(bytes). Decode: Convert.FromBase64String(str) returns byte[]. For strings: Encoding.UTF8.GetBytes(str) before encoding; Encoding.UTF8.GetString(bytes) after decoding. URL-safe: replace + with -, / with _; TrimEnd('='). High-performance .NET 5+: System.Buffers.Text.Base64.EncodeToUtf8().
Examples
Encode a string
using System;
using System.Text;
byte[] bytes = Encoding.UTF8.GetBytes("Hello, World!");
string encoded = Convert.ToBase64String(bytes);
Console.WriteLine(encoded);
// SGVsbG8sIFdvcmxkIQ== Decode a string
byte[] decoded = Convert.FromBase64String("SGVsbG8sIFdvcmxkIQ==");
string text = Encoding.UTF8.GetString(decoded);
Console.WriteLine(text);
// Hello, World! URL-safe encoding
string urlSafe = Convert.ToBase64String(bytes)
.Replace('+', '-')
.Replace('/', '_')
.TrimEnd('=');
// Uses base64url alphabet, no padding Encode a file
byte[] fileBytes = File.ReadAllBytes("image.png");
string encoded = Convert.ToBase64String(fileBytes);
File.WriteAllText("image.b64", encoded); Verify with the Base64 Text & File Encoder/Decoder tool.
Encode a string
using System;
using System.Text;
byte[] bytes = Encoding.UTF8.GetBytes("Hello, World!");
string encoded = Convert.ToBase64String(bytes);
Console.WriteLine(encoded);
// SGVsbG8sIFdvcmxkIQ== Code says: SGVsbG8sIFdvcmxkIQ==
- 1.
Microsoft, "Convert.FromBase64String(String) Method," learn.microsoft.com, accessed June 2026. https://learn.microsoft.com/en-us/dotnet/api/system.convert.frombase64string?view=net-9.0
- 2.
Microsoft, "Base64 Class (System.Buffers.Text)," learn.microsoft.com, accessed June 2026. https://learn.microsoft.com/en-us/dotnet/api/system.buffers.text.base64?view=net-9.0
- 3.
S. Josefsson, "The Base16, Base32, and Base64 Data Encodings," RFC 4648, IETF, October 2006. https://datatracker.ietf.org/doc/html/rfc4648
- 4.
.NET Foundation, "Convert.cs," github.com, accessed June 2026. https://raw.githubusercontent.com/dotnet/runtime/main/src/libraries/System.Private.CoreLib/src/System/Convert.cs
- 5.
OWASP Foundation, "Password Storage Cheat Sheet," cheatsheetseries.owasp.org, accessed June 2026. https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html
- 6.
.NET Foundation, "Add Convert Span-based APIs," github.com, accessed June 2026. https://github.com/dotnet/runtime/issues/22848
It throws System.FormatException for input that contains non-Base64 characters or incorrect padding. Wrap in try/catch when handling external input. In .NET 7+, Convert.TryFromBase64String provides a bool return pattern.
System.Convert does not provide URL-safe encoding. For ASP.NET Core projects, Microsoft.AspNetCore.WebUtilities includes Base64UrlTextEncoder with ToBase64String and FromBase64String methods.
Convert.ToBase64String allocates a new string each time. System.Buffers.Base64.EncodeToUtf8() writes into Span<byte> buffers without allocation, reducing GC pressure in hot paths.
Read the file in chunks of 3 × N bytes using FileStream.Read() in a loop. Encode each chunk with Convert.ToBase64String() and write the result to a StreamWriter. Only the current chunk lives in memory at once.
Yes. CapyToolkit produces standard Base64 with = padding , the format Convert.FromBase64String() expects. Copy the output directly into your C# code without any transformation.
Base64 Encode and Decode in Ruby
Ruby exposes Base64 as a small standard-library module with deliberately different methods.
Ruby provides Base64 encoding through the Base64 module. Require 'base64' before calling its methods.1
Three encoding methods cover the main use cases: encode64() with newline wrapping, strict_encode64() without newlines, and urlsafe_encode64() for URL-safe output. URL-safe output uses the RFC 4648 alphabet, replacing + with - and / with _; set padding: false when the receiver expects an unpadded token.2 Ruby strings can carry binary data, so read file bytes first, then pass the resulting String to Base64.strict_encode64().
Core API and encoding variants
Base64.encode64(str) encodes and wraps output at 60 characters with newlines, while Base64.strict_encode64(str) produces a single-line string without any line breaks that could corrupt downstream protocols.1 The two methods accept the same input but differ only in whether the output contains embedded newline characters, so the choice between them depends entirely on whether the receiving system treats newlines as delimiters or as data within the encoded value.
Matching Ruby methods to context
Base64.urlsafe_encode64(str, padding: true) produces URL-safe output with - and _ replacing + and /. Consequently, strict_encode64 is the right default for JSON values, URLs, and HTTP headers. Furthermore, Base64.decode64() accepts wrapped and unwrapped input; strict_decode64() rejects invalid characters; urlsafe_decode64() reverses the URL-safe encoding. Choosing the wrong method for the transport context is a surprisingly common source of bugs in Ruby APIs, because encode64 silently injects newline characters into strings that other systems expect to be single-line, causing authentication failures and malformed JSON. The Ruby community converged on strict_encode64 as the default recommendation precisely because the silent newline injection in encode64 is so difficult to debug when a downstream parser rejects a credential that looks correct in application logs.
Strict encoding as the default also keeps logs honest, because the value you see during debugging is the exact value that reaches the transport, with no hidden newlines inserted between what the code produced and what the parser receives. It also means a failed credential shows up identically in the application log and the transport trace, so you debug the real string rather than a wrapped one that only exists in one layer.
Working with files and binary data
Ruby strings hold binary data: File.binread(path) reads file bytes as a String, and Base64.strict_encode64() encodes that String directly. For very large files, read in multiples-of-3-byte chunks to avoid padding mid-stream: chunk_size = 3 * 4096; File.open(path, 'rb') { |f| f.each_bytes(chunk_size) { |chunk| output << Base64.strict_encode64(chunk) } }. Base64 changes three input bytes into four output characters, so chunking on a 3-byte boundary keeps intermediate blocks aligned until the final chunk.2 This concatenates clean Base64 without padding at chunk boundaries except the last. Furthermore, Base64.encode64 is not suitable for HTTP headers or JSON because its 60-character line wrapping embeds newline characters; JSON strings must escape control characters such as line feed.3
Security and common mistakes
Base64 is encoding, not encryption, which means it provides no protection for credentials, API keys, or personally identifiable information that must remain confidential. Never use Base64 to protect sensitive values from anyone who can read the encoded string; it exists solely to make binary data safe for text-based protocols. This distinction matters because encoding is a reversible transformation with no key, while encryption requires the corresponding key to recover the original data, so the two serve fundamentally different purposes in application design.
Avoiding newline and binary traps
The most common Ruby mistake is using encode64() (which adds newlines) in a context that expects strict_encode64() (no newlines); HTTP headers and JSON values need single-line strings, and JSON strings must escape control characters such as line feed. For URL-safe output in tokens, use urlsafe_encode64(str, padding: false) only when the receiver expects an unpadded RFC 4648 token. For file encoding, use binread rather than read when you need byte-for-byte input. Another subtle trap is calling encode64 on a string that already contains Base64 characters without realizing the input was already encoded, which produces double-encoded output that decodes to the original Base64 string rather than the original data, a bug that passes initial smoke tests but fails when the decoded bytes must be interpreted as binary content.
Encoding large binary files in streaming chunks
Reading a large binary file in one call with File.binread(path) loads the entire file into memory before encoding begins. For files over a few megabytes, a chunked approach keeps memory use bounded: read the file in blocks of 3 times 4096 bytes (12,288 bytes per chunk) using File.open(path, 'rb') { |f| while (chunk = f.read(12_288)); output << Base64.strict_encode64(chunk); end }. The multiple-of-3 block size ensures each chunk encodes to a complete sequence of 4-character Base64 groups with no mid-stream padding.
Concatenating the encoded chunks produces a valid single-line Base64 string for the entire file. Because each chunk ends on a 3-byte boundary, no = padding appears until the final chunk, where the remaining bytes may be 1 or 2 fewer than a full group. Verify the encoded result by decoding and comparing byte lengths against the original file size.
Base64 in Rails mailers and Active Storage
Rails ActionMailer encodes attachments automatically when you call attachments['report.pdf'] = File.binread(path), handling the Base64 encoding internally.4 The mailer can build a multipart message with a Base64 encoded copy of the attachment, so you do not need to call Base64.strict_encode64 yourself when working through ActionMailer's attachment API. This internal encoding uses the standard MIME Base64 alphabet with 76-character line wrapping, which is required by the MIME email specification and ensures compatibility with all mail clients.
Encoding binary data in JSON API responses
For JSON API responses that include binary data such as generated thumbnails or signed certificates, Base64.strict_encode64(bytes) is the correct method to use. Avoid encode64 in JSON response bodies: its 60-character line wrapping embeds literal newline characters inside the JSON string value, and JSON strings must escape control characters such as line feed.3 In Active Storage, blob.download returns raw bytes; wrap them with strict_encode64 before placing the result in a JSON field or an email template body. Active Storage's built-in URL helpers are usually preferable to inline Base64 for large files, but for small thumbnails that must render in a single API response without a second HTTP request, the strict_encode64 approach keeps the payload self-contained.
When to use this
Use Base64.strict_encode64() as the default in Ruby , it handles any string, produces no newlines, and works in HTTP headers, JSON, and URLs. Use urlsafe_encode64() with padding: false for JWT tokens, OAuth parameters, and URL path segments that need an unpadded5 RFC 4648 token.
Notes
require 'base64' (standard library). strict_encode64(str): single-line standard Base64. encode64(str): 60-char line-wrapped. urlsafe_encode64(str, padding: true/false): URL-safe. Use File.binread for binary files. strict_decode64 rejects invalid input; decode64 is permissive.
Examples
Encode a string (strict)
require 'base64'
encoded = Base64.strict_encode64('Hello, World!')
puts encoded
# SGVsbG8sIFdvcmxkIQ== Decode a string
require 'base64'
decoded = Base64.strict_decode64('SGVsbG8sIFdvcmxkIQ==')
puts decoded
# Hello, World! URL-safe without padding
require 'base64'
encoded = Base64.urlsafe_encode64('user+name/data', padding: false)
# No +, /, or = characters Encode a binary file
require 'base64'
content = File.binread('image.png')
encoded = Base64.strict_encode64(content)
File.write('image.b64', encoded) Verify with the Base64 Text & File Encoder/Decoder tool.
Encode a string (strict)
require 'base64'
encoded = Base64.strict_encode64('Hello, World!')
puts encoded
# SGVsbG8sIFdvcmxkIQ== Code says: SGVsbG8sIFdvcmxkIQ==
- 1.
Ruby, "Base64 module," raw.githubusercontent.com, accessed June 2026. https://raw.githubusercontent.com/ruby/base64/7ec2861d800c32793816ffb9885921192011ca1f/lib/base64.rb
- 2.
S. Josefsson, "The Base16, Base32, and Base64 Data Encodings," RFC 4648, IETF, October 2006. https://datatracker.ietf.org/doc/html/rfc4648
- 3.
T. Bray, "The JavaScript Object Notation (JSON) Data Interchange Format," RFC 8259, IETF, December 2017. https://datatracker.ietf.org/doc/html/rfc8259
- 4.
Rails, "ActionMailer::Base," raw.githubusercontent.com, accessed June 2026. https://raw.githubusercontent.com/rails/rails/v7.2.3.1/actionmailer/lib/action_mailer/base.rb
- 5.
"Base64," Wikipedia, accessed June 2026. https://en.wikipedia.org/wiki/Base64
encode64() wraps output at 60 characters with newline characters. strict_encode64() produces a single-line string without any line breaks. Use strict_encode64() in all contexts where a single-line string is expected: HTTP headers, JSON values, URL parameters.
Ruby's encode64() wraps at 60 characters (not 76). Python's base64.encodebytes() wraps at 76. MIME standard is 76. If you need MIME-compatible line-wrapping, be aware of the 60-character limit, or apply your own 76-character wrapping with strict_encode64.
Call encode.gsub(/\s/, "") to strip whitespace before passing to strict_decode64(). Alternatively, use decode64() which is permissive about non-Base64 characters.
No for typical Ruby installations: the Base64 module is available when you require "base64". Adding gem "base64" to your Gemfile can still be useful in production applications when you want to pin the exact implementation version.
Yes. strict_encode64 produces standard Base64 that the CapyToolkit decoder accepts without any transformation.
Base64 Encode and Decode in Swift
On Apple platforms, Foundation gives Swift a compact Data API for Base64.
Swift encodes and decodes Base64 through the Foundation framework's Data type.
Data.base64EncodedString() produces standard Base64 with = padding; Data(base64Encoded:) decodes it back to Data.1 For URL-safe Base64, replace + with -, replace / with _, and remove = padding only when the receiver expects an unpadded token.2 JWTs use URL-safe Base64url parts separated by periods, so prefer a JWT library for token handling rather than hand-rolling the alphabet conversion.3 The same rule applies to app code: keep transport conversion separate from storage, because the Keychain stores Data directly.
Core API and encoding variants
Data.base64EncodedString(options:) returns a standard Base64 string with = padding.1 Passing .lineLength64Characters or .lineLength76Characters wraps the output for PEM or MIME compatibility, and the line ending options control whether wrapped output ends with carriage return or line feed characters.4 Data(base64Encoded: string, options:) decodes a string and returns Data? , nil if the input is invalid. Consequently, always unwrap the optional before using the decoded bytes. Furthermore, passing .ignoreUnknownCharacters in options makes the decoder skip whitespace and line breaks, useful for decoding MIME-wrapped or PEM-formatted input. For string-to-Data conversion before encoding, always use Data(str.utf8) rather than relying on a default encoding, because the .utf8 view produces the same byte sequence across all platforms and avoids the ambiguity of Swift's default string-to-data conversion behavior.
Working with files and binary data
Swift file encoding starts by loading bytes into Data, then calling data.base64EncodedString() on that Data. For images, convert the image to PNG or JPEG Data first, then encode that Data. For remote data from a URLSession task, wait until the response Data is available before calling base64EncodedString(). This ordering matters because calling base64EncodedString() on an empty Data value produces an empty string, which is rarely the intended result when the network request fails silently.
Encoding image bytes and remote responses
For large files where memory is constrained, read chunks of bytes into Data and encode each chunk separately; FileHandle exposes bounded reads that return a fixed count of bytes as Data.4 Base64 maps three input bytes to four output characters, so chunking on a 3-byte boundary keeps intermediate blocks aligned until the final chunk.2 When you encode a large image for a JSON API upload, the chunked approach prevents the app from holding both the raw pixel data and the Base64 string in memory simultaneously, which is critical on older iOS devices with 1 GB of RAM.
Chunking on the 3-byte boundary also aligns each encoded block so no padding appears in the middle of the stream, which keeps the concatenated result valid without a final reassembly step on the device. It also means the memory peak stays flat as the file grows, because the app only ever holds one chunk of raw bytes and one chunk of encoded text rather than the entire asset twice.
Security and common mistakes
Base64 is encoding, not encryption, which means it provides no protection for sensitive data on any platform including Apple devices. Any Base64-encoded value can be decoded by anyone who has access to the encoded string, with no key or credential required to recover the original bytes, so it must never be treated as a confidentiality mechanism.
Protecting decoded secrets on Apple platforms
Never store API keys or passwords as Base64 in app bundles or UserDefaults; UserDefaults is intended for nonsensitive app-specific configuration, and device backups can include defaults databases.5 Store secrets in the iOS Keychain, which is designed for passwords, cryptographic keys, certificates, and other small secret values.6 The most common mistake is passing a URL-safe Base64 string to Data(base64Encoded:), because the decoder rejects - and _ as invalid characters. Replace - with + and _ with / before decoding: base64url.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/"). Add padding if needed before decoding. A second frequent issue is force-unwrapping the result of Data(base64Encoded:) without handling the nil case, which crashes the app at runtime when the input contains any invalid character. Use guard let or optional binding to surface the decoding failure gracefully.
In async Swift code and Combine pipelines
In async Swift code, keep file I/O and large encoding work off the main actor so UI updates are not delayed while Data is loaded or processed by the asynchronous runtime. Once Data is available, base64EncodedString() is a synchronous call that returns the encoded string immediately without blocking. The main actor is responsible for all UI work, so any synchronous call that takes measurable time should run on a background context instead.
Keeping UI responsive in async code
Keep user-facing progress updates on the main actor after the synchronous encoding finishes. In Combine, map operators can handle encoding inline after a publisher has produced Data. For large files, prefer chunked reads and avoid building one very large intermediate Data value before encoding. Moving the encoding work to a background task with async let or a detached actor keeps the main thread free to animate progress indicators, which matters when the user is waiting on a multi-megabyte upload and expects the interface to remain responsive.
Keychain storage and Base64 transport in iOS
The iOS Keychain stores arbitrary Data blobs directly without requiring Base64 encoding, which is the correct approach for persistent secret storage on Apple devices. Encoding key material as a Base64 string and storing the string in UserDefaults is a common antipattern that exposes secrets to backup and device restore flows.
For scenarios where binary values must travel through a text channel, encode the Keychain-retrieved Data as Base64 for transport and decode it on the receiving device before storing in the local Keychain. Never log the Base64 string or the decoded bytes; treat them with the same care as the raw key material they represent. Logging a Base64-encoded private key is equivalent to logging the key itself, because anyone with access to the log can decode it in one step.
When to use this
Use Data.base64EncodedString() for encoding images in API requests, generating data URIs for WKWebView, and encoding binary payloads in JSON. Use a JWT library for token handling because JWTs use Base64url parts, and manual alphabet conversion in Swift is error-prone.3
Notes
Foundation required. Encode: Data.base64EncodedString(). Decode: Data(base64Encoded: str, options: .ignoreUnknownCharacters). String to Data: str.data(using: .utf8)?.base64EncodedString(). URL-safe: replacingOccurrences('+' with '-', '/' with '_'). For images: UIImage.pngData()?.base64EncodedString().
Examples
Encode a string
import Foundation let str = "Hello, World!" let encoded = Data(str.utf8).base64EncodedString() print(encoded) // SGVsbG8sIFdvcmxkIQ==
Decode a string
let decoded = Data(base64Encoded: "SGVsbG8sIFdvcmxkIQ==")! let text = String(data: decoded, encoding: .utf8)! print(text) // Hello, World!
URL-safe encoding for JWT
func base64url(_ data: Data) -> String {
return data.base64EncodedString()
.replacingOccurrences(of: "+", with: "-")
.replacingOccurrences(of: "/", with: "_")
.replacingOccurrences(of: "=", with: "")
} Encode a UIImage
let image = UIImage(named: "icon")!
if let pngData = image.pngData() {
let encoded = pngData.base64EncodedString()
let dataUri = "data:image/png;base64," + encoded
} Verify with the Base64 Text & File Encoder/Decoder tool.
Encode a string
import Foundation let str = "Hello, World!" let encoded = Data(str.utf8).base64EncodedString() print(encoded) // SGVsbG8sIFdvcmxkIQ==
Code says: SGVsbG8sIFdvcmxkIQ==
- 1.
Swift Foundation, "NSData.swift," github.com, accessed June 2026. https://github.com/apple/swift-corelibs-foundation/blob/5db60c05406d8829956df9c4ec4fc72665cf6638/Sources/Foundation/NSData.swift
- 2.
S. Josefsson, "The Base16, Base32, and Base64 Data Encodings," RFC 4648, IETF, October 2006. https://datatracker.ietf.org/doc/html/rfc4648
- 3.
M. Jones, J. Bradley, and N. Sakimura, "JSON Web Token (JWT)," RFC 7519, IETF, May 2015. https://datatracker.ietf.org/doc/html/rfc7519
- 4.
Swift Foundation, "FileHandle.swift," github.com, accessed June 2026. https://github.com/apple/swift-corelibs-foundation/blob/eec4b26deee34edb7664ddd9c1222492a399d122/Sources/Foundation/FileHandle.swift
- 5.
Apple, "UserDefaults," developer.apple.com, accessed June 2026. https://developer.apple.com/documentation/foundation/userdefaults
- 6.
Apple, "Using the keychain to manage user secrets," developer.apple.com, accessed June 2026. https://developer.apple.com/documentation/security/using-the-keychain-to-manage-user-secrets
The input contains characters outside the Base64 alphabet (including URL-safe characters - and _), incorrect padding, or invalid length. Pass .ignoreUnknownCharacters to skip whitespace. For URL-safe Base64, convert - to + and _ to / before decoding.
lineLength64Characters wraps at 64 chars (PEM), lineLength76Characters at 76 (MIME). endLineWithCarriageReturn and endLineWithLineFeed control line ending style. Passing no options produces a single-line, non-wrapped string.
Strip the PEM header and footer, join the lines, and pass to Data(base64Encoded: pem, options: .ignoreUnknownCharacters). The option handles the line breaks without manual stripping.
WKWebView and SFSafariViewController render data URIs in HTML content. For inline images in SwiftUI, load the decoded Data into a UIImage and wrap in Image(uiImage:) rather than using a data URI.
Yes. Encode test data in CapyToolkit and compare against your Swift output. All processing runs locally in your browser , no data is sent to a server.
Base64 Encode and Decode in Kotlin
Kotlin makes Base64 explicit by staying on the JVM byte-array path.
Kotlin targets the JVM so it uses java.util.Base64 directly, with no additional dependencies needed on Java 8 and later JVMs.1
The API provides three encoders: getEncoder() for standard Base64, getUrlEncoder() for URL-safe Base64, and getMimeEncoder() for MIME-formatted output with line wrapping. All return an Encoder whose encodeToString() and decode() methods work directly with ByteArray and String. URL-safe Base64 is the form used by JWT payloads and URL query parameters; MIME Base64 is the wrapped form used for email attachments. Pick the encoder name in the helper so callers see the transport before they call it.
Core API: encoders and decoders
java.util.Base64 exposes static factory methods that return either an Encoder or a Decoder object, and Kotlin calls these directly since it runs on the JVM with full access to the Java standard library without any additional dependencies.1 The factory pattern means you choose the variant once when obtaining the encoder or decoder, and all subsequent calls to encode or decode use that same configuration, which avoids repeating format flags at every call site.
Selecting the JVM encoder for the target format
Call Base64.getEncoder().encodeToString(bytes) to encode, and Base64.getDecoder().decode(string) to decode back to a ByteArray. For URL-safe output (no + or / characters) use Base64.getUrlEncoder() and Base64.getUrlDecoder(), which is the correct choice for JWT payloads and URL query parameters.2 MIME encoding (Base64.getMimeEncoder()) wraps output at 76 characters and adds CRLF line separators, matching the RFC 2045 format required for email attachments.3 Picking the wrong encoder for the target transport is one of the most common interoperability bugs in JVM services, because the standard encoder silently produces + and / characters that break URL-based token flows and corrupt filenames on systems that treat slashes as path separators.
Choosing the encoder once at acquisition also keeps the configuration out of the call sites, so the format flag travels with the encoder object rather than being repeated and possibly contradicted at every encode call. It also makes the choice grep-able in review, because a single getUrlEncoder() call tells an auditor exactly which alphabet every downstream encode uses.
Working with strings and files
To encode text, convert to UTF-8 bytes first: text.toByteArray(Charsets.UTF_8). To decode back to text, call String(decodedBytes, Charsets.UTF_8) after decoding, ensuring the charset matches what was used during the encoding step.4 Using a mismatched charset between encoding and decoding produces garbled output without raising an exception, which makes this mistake especially dangerous in production systems where the wrong charset silently corrupts every decoded value.
Encoding JVM strings and file bytes
For files, read all bytes with File("path").readBytes() and pass them directly to encodeToString(). This approach works for files that fit comfortably in memory, but for larger files you should consider the streaming approach because readBytes() loads the entire file into a single byte array, which on a multi-gigabyte file can exhaust the JVM heap and crash the process.
For large files, use OutputStream wrapping: Base64.getEncoder().wrap(outputStream) returns an OutputStream that Base64-encodes everything written through it, which avoids loading the entire file into memory. Likewise, Base64.getDecoder().wrap(inputStream) decodes on the fly during reading. The wrap approach is particularly valuable in Android applications that need to encode large media files for upload, because it avoids the OutOfMemoryError that occurs when the entire file is loaded into a single byte array before encoding begins. In a Kotlin coroutine context, wrap the blocking I/O in Dispatchers.IO so the encoding work does not block the main thread and trigger an Application Notifying Response (ANR) dialog on Android.
Security and common mistakes
Base64 is encoding, not encryption, which means it provides no protection for passwords, authentication tokens, or personal data that must remain confidential. Do not use Base64 as a security measure in any context. The distinction matters on Android as on any other platform, because an attacker with access to the APK or the network traffic can decode any Base64 value as easily as the application itself can.
Matching charset, padding, and parser expectations
Always pass Charsets.UTF_8 explicitly when converting text so the byte representation matches the protocol you are interoperating with.2 Additionally, getUrlEncoder() by default appends = padding; call withoutPadding() to strip it: Base64.getUrlEncoder().withoutPadding().encodeToString(bytes). JWTs use Base64url parts, so strip padding only when the token receiver expects an unpadded token.5 Validate decoded binary input before passing it to parsers, because malformed bytes can crash downstream deserialization code in ways that are difficult to trace back to the original encoding step. A practical validation step is to check the first few bytes of the decoded output against known magic byte sequences for the expected file format, which catches the case where a client sends a ZIP file disguised as a PNG by the Content-Type header.
Android-specific Base64 patterns
For JVM Kotlin code, prefer java.util.Base64 because it keeps the same API across server, desktop, and recent Android runtimes without any additional dependencies. If you need a single helper for older or non-JVM targets, keep the Base64 conversion behind one small adapter so callers do not depend on platform-specific flags.
Avoid duplicating encoding logic across modules. A single adapter makes it easier to test padding, line wrapping, and URL-safe output in one place before callers serialize JSON, build headers, or write files. Document the chosen variant in the adapter name, such as base64UrlNoPadding, so future callers do not accidentally mix standard and URL-safe values. This small naming choice prevents token bugs that only appear after deployment.
Before merging the adapter, add one round-trip test for each transport: standard JSON, JWT payloads, and MIME output. Those checks catch accidental charset, padding, or decoder mismatches before production callers depend on the helper, saving debugging time when a token that works in development fails in production because of a subtle encoding mismatch.
In Kotlin Multiplatform Mobile projects
In Kotlin Multiplatform projects, choose a Base64 implementation that is available to every target platform, not just the JVM. Okio exposes ByteString.base64() and ByteString.base64Url() from common code, which is useful when JVM-only java.util.Base64 is not available everywhere.6 Relying on platform-specific APIs in shared code forces conditional compilation and makes the shared layer harder to test, so a common implementation keeps the multiplatform project simpler.
For small projects without Okio, place a pure Kotlin Base64 implementation in the commonMain source set so it compiles for every target platform. Share encoding logic through the common source set rather than duplicating it in androidMain and iosMain. A single implementation ensures consistent encoding behavior and a single maintenance point when the implementation needs updating. The Ktor HTTP client and other multiplatform libraries expect Base64 strings from shared code, so getting the encoding right in commonMain prevents subtle platform-specific bugs where the same payload encodes differently on iOS versus Android.
When to use this
Use java.util.Base64 in Kotlin for encoding binary data into JSON strings, building HTTP Basic Auth headers, creating JWTs with URL-safe Base64, embedding images in responses, or reading PEM-encoded certificates.5 The MIME encoder is the right choice for email attachments because RFC 2045 defines the wrapped 76-character MIME form.3
Notes
Import java.util.Base64. Use Base64.getEncoder() for standard, Base64.getUrlEncoder() for URL-safe, and Base64.getMimeEncoder() for MIME. Call withoutPadding() on URL encoder for JWT use. Convert strings with .toByteArray(Charsets.UTF_8) and String(bytes, Charsets.UTF_8).
Examples
Encode a string
import java.util.Base64 val text = "Hello, World!" val encoded = Base64.getEncoder().encodeToString(text.toByteArray(Charsets.UTF_8)) println(encoded) // SGVsbG8sIFdvcmxkIQ==
Decode a string
import java.util.Base64 val encoded = "SGVsbG8sIFdvcmxkIQ==" val decoded = String(Base64.getDecoder().decode(encoded), Charsets.UTF_8) println(decoded) // Hello, World!
URL-safe without padding
import java.util.Base64
val payload = "user+data/test"
val encoded = Base64.`getUrlEncoder().withoutPadding()`
.encodeToString(payload.toByteArray(Charsets.UTF_8))
println(encoded) // dXNlcituYW1lL2VtYWls Encode a file
import java.io.File
import java.util.Base64
val bytes = File("image.png").readBytes()
val encoded = Base64.getEncoder().encodeToString(bytes)
println("${encoded.length} chars") Verify with the Base64 Text & File Encoder/Decoder tool.
Encode a string
import java.util.Base64 val text = "Hello, World!" val encoded = Base64.getEncoder().encodeToString(text.toByteArray(Charsets.UTF_8)) println(encoded) // SGVsbG8sIFdvcmxkIQ==
Code says: SGVsbG8sIFdvcmxkIQ==
- 1.
Oracle, "Base64 (Java Platform SE 8)," docs.oracle.com, accessed June 2026. https://docs.oracle.com/javase/8/docs/api/java/util/Base64.html
- 2.
S. Josefsson, "The Base16, Base32, and Base64 Data Encodings," RFC 4648, IETF, October 2006. https://datatracker.ietf.org/doc/html/rfc4648
- 3.
N. Freed and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies," RFC 2045, IETF, November 1996. https://www.rfc-editor.org/rfc/rfc2045.html
- 4.
Oracle, "StandardCharsets (Java Platform SE 8)," docs.oracle.com, accessed June 2026. https://docs.oracle.com/javase/8/docs/api/java/nio/charset/StandardCharsets.html
- 5.
M. Jones, J. Bradley, and N. Sakimura, "JSON Web Token (JWT)," RFC 7519, IETF, May 2015. https://datatracker.ietf.org/doc/html/rfc7519
- 6.
Square, "ByteString.kt," github.com, accessed June 2026. https://github.com/square/okio/blob/master/okio/src/commonMain/kotlin/okio/ByteString.kt
No. Kotlin runs on the JVM and can use java.util.Base64 directly, which is available in Java 8 and later. No additional dependencies are needed.
getEncoder() produces standard Base64 with + and / characters. getUrlEncoder() replaces these with - and _ so the output is safe for URL query parameters and JWT payloads without percent-encoding.
Chain .withoutPadding() onto the encoder: Base64.getUrlEncoder().withoutPadding().encodeToString(bytes). This is commonly required by JWT libraries that expect padding-free Base64url.
Yes. Base64.getEncoder().wrap(outputStream) returns an OutputStream that encodes data as it is written. Base64.getDecoder().wrap(inputStream) decodes during reading. This avoids loading entire files into memory.
No. Base64 is reversible encoding with no key , anyone can decode it. CapyToolkit encodes and decodes entirely in your browser, so no data reaches any server.
Base64 Encode and Decode in PowerShell
For PowerShell scripts, the byte model decides the result before the Base64 call runs.1
PowerShell exposes Base64 through the .NET System.Convert class, so scripts call [Convert]::ToBase64String() and [Convert]::FromBase64String() without loading an extra module.
Treat the result as a byte representation, not text protection. For cross-platform text, convert with UTF-8 bytes before encoding; .NET's Unicode encoding is UTF-16 little-endian and will not match tools that expect UTF-8.2 Put the encoding step in a helper with the target protocol in its name, because the same Base64 API can produce different bytes.
Encoding and decoding strings
The canonical PowerShell pattern for string-to-Base64 conversion is: $bytes = [System.Text.Encoding]::UTF8.GetBytes($text) followed by [Convert]::ToBase64String($bytes). For decoding, reverse the process with [Convert]::FromBase64String($encoded) returning a byte array, then [System.Text.Encoding]::UTF8.GetString($bytes) to recover the original text.12 Getting the encoding step wrong produces output that looks like valid Base64 but decodes to different bytes, which is why specifying UTF-8 explicitly matters more in PowerShell than in languages where UTF-8 is already the default.
Choosing UTF-8 instead of PowerShell defaults
The UTF8 encoding is explicit and critical because PowerShell's default [System.Text.Encoding]::Unicode is UTF-16LE, which produces output that no cross-platform tool can decode correctly. Always specify UTF8 unless you specifically need UTF-16 encoded payloads, such as -EncodedCommand arguments that intentionally use UTF-16LE. The mismatch between UTF-8 and UTF-16LE is one of the hardest encoding bugs to diagnose in cross-platform scripts, because the Base64 output looks valid but decodes to completely different bytes on the receiving end, producing authentication failures that are invisible without a hex dump comparison.
Specifying the encoding at the byte step also keeps PowerShell scripts portable, so the same command produces identical bytes on Windows, Linux, and macOS instead of diverging by platform default. It also removes a whole category of silent failures where a script that works on one machine produces unreadable credentials on another with no error message.
Working with files
For file encoding, read the binary content and convert in one line: [Convert]::ToBase64String([System.IO.File]::ReadAllBytes('C:\path\file.pdf'))]. For decoding a file back from Base64, pipe the output to [System.IO.File]::WriteAllBytes('output.pdf', [Convert]::FromBase64String($encoded))].3 This one-line approach loads the entire file into memory, so it works well for small to medium files but can cause an OutOfMemoryException on very large files where a streaming approach would be more appropriate.
Keeping binary file reads byte-oriented
The -EncodedCommand parameter on powershell.exe and pwsh.exe expects a UTF-16LE Base64-encoded command string, so use [System.Text.Encoding]::Unicode.GetBytes() rather than UTF8 for that specific use case.4 If you need 76-character line wrapping for MIME or PEM output, pass Base64FormattingOptions.InsertLineBreaks as the second argument to ToBase64String(); RFC 2045 defines the wrapped MIME body format.5 When you read a binary file with Get-Content instead of ReadAllBytes, the file content passes through the PowerShell text pipeline which applies the system default encoding, corrupting any byte sequence that does not represent valid text in that encoding and producing Base64 output that cannot be decoded back to the original file.
Security and common mistakes
Base64 is encoding, not obfuscation, and PowerShell's -EncodedCommand feature is documented as a Base64 transport mechanism, so it should not be treated as a way to protect sensitive logic from inspection. Anyone with access to the script or the process memory can decode the Base64 payload and recover the original command text, so this mechanism only protects against casual reading, not against a determined inspection.
Keeping automation bytes explicit
The most common mistake is forgetting to specify UTF8 encoding, producing UTF-16LE output that differs from what bash, Python, or other tools produce. A second common mistake is using Get-Content to read a binary file without byte-oriented options, which can corrupt binary data by interpreting it as text. Test your encoding by decoding in a second step and comparing the output. A third issue is that PowerShell's pipeline applies default formatting to byte arrays, so a [byte[]] value that passes through Write-Output or gets interpolated into a string may produce unexpected text representations. Always use [Convert]::ToBase64String() directly on the byte array rather than relying on implicit string conversion.
Automation payloads and PowerShell remoting
For automation payloads, encode the exact bytes you intend to transmit and keep the encoding choice close to the data rather than relying on shell defaults. Use UTF-8 for string values that must match across authoring and target machines, and keep binary values as byte arrays until the final Base64 step. Mixing up these two encoding choices is one of the most common sources of cross-platform encoding bugs in PowerShell automation scripts, because the resulting Base64 output looks valid in both cases but decodes to completely different bytes on the receiving end.
For PowerShell remoting with -EncodedCommand, the command must be encoded as UTF-16LE: [System.Text.Encoding]::Unicode.GetBytes($command) before encoding with [Convert]::ToBase64String(). Sending UTF-8-encoded Base64 to -EncodedCommand produces incorrect execution or a syntax error on the remote host because the remote endpoint expects UTF-16LE bytes and decodes the Base64 payload accordingly, so the command that arrives on the remote host is a garbled string of misinterpreted characters rather than the intended PowerShell script. For ordinary API payloads and file exchange, however, UTF-8 remains the safer default because it matches most web services, CI systems, and non-Windows tooling. Keep both paths in separate helpers so a future maintainer cannot mix remoting and transport encoding by accident. Before deploying the helper, test both branches with the same literal text to verify that the UTF-8 helper matches external tools while the remoting helper executes the intended command on the target host.
Between Windows PowerShell 5.1 and PowerShell 7
[Convert]::ToBase64String() behaves consistently because it is a .NET conversion method rather than a shell-specific formatter. The practical differences appear in byte array handling and runtime availability. In Windows PowerShell 5.1, use documented byte-oriented file reading options for binary files. In PowerShell 7, use the current byte-stream options for the same goal.
Avoid tying shared scripts to a single edition unless the deployment target is fixed. Test your Base64 scripts in both editions if you maintain scripts deployed to both environments. PowerShell 7 also introduces the -AsPlainText parameter for ConvertTo-SecureString and improved cross-platform behavior, so scripts that conditionally import modules or use edition-specific cmdlets should detect $PSVersionTable.PSEdition at runtime and branch accordingly rather than assuming the executing edition from the file extension alone.
When to use this
Use PowerShell Base64 when embedding binary data in JSON payloads for REST APIs, encoding credentials for Basic Auth headers, passing scripts to -EncodedCommand, or serializing certificate thumbprints and keys in automation scripts.
Notes
Use [System.Text.Encoding]::UTF8.GetBytes() before encoding and [System.Text.Encoding]::UTF8.GetString() after decoding to ensure cross-platform compatibility. For -EncodedCommand, use Unicode (UTF-16LE) encoding instead. For files, use [System.IO.File]::ReadAllBytes() to avoid text encoding issues.
Examples
Encode a string
$text = "Hello, World!" $bytes = [System.Text.Encoding]::UTF8.GetBytes($text) $encoded = [Convert]::ToBase64String($bytes) Write-Output $encoded # SGVsbG8sIFdvcmxkIQ==
Decode a string
$encoded = "SGVsbG8sIFdvcmxkIQ==" $bytes = [Convert]::FromBase64String($encoded) $text = [System.Text.Encoding]::UTF8.GetString($bytes) Write-Output $text # Hello, World!
Encode a file
$encoded = [Convert]::ToBase64String(
[System.IO.File]::ReadAllBytes("C:\image.png")
)
Set-Content -Path "image.b64" -Value $encoded Decode a file
$encoded = Get-Content "image.b64" -Raw
$bytes = [Convert]::FromBase64String($encoded.Trim())
[System.IO.File]::WriteAllBytes("output.png", $bytes) Verify with the Base64 Text & File Encoder/Decoder tool.
Encode a string
$text = "Hello, World!" $bytes = [System.Text.Encoding]::UTF8.GetBytes($text) $encoded = [Convert]::ToBase64String($bytes) Write-Output $encoded # SGVsbG8sIFdvcmxkIQ==
Code says: SGVsbG8sIFdvcmxkIQ==
- 1.
Microsoft, "Convert.ToBase64String Method," learn.microsoft.com, accessed June 2026. https://learn.microsoft.com/en-us/dotnet/api/system.convert.tobase64string?view=net-8.0
- 2.
Microsoft, "Encoding.GetBytes Method," learn.microsoft.com, accessed June 2026. https://learn.microsoft.com/en-us/dotnet/api/system.text.encoding.getbytes?view=net-10.0
- 3.
MicrosoftDocs, "Get-Content.md," github.com, accessed June 2026. https://github.com/MicrosoftDocs/PowerShell-Docs/blob/main/reference/7.4/Microsoft.PowerShell.Management/Get-Content.md
- 4.
MicrosoftDocs, "about_Pwsh.md," github.com, accessed June 2026. https://github.com/MicrosoftDocs/PowerShell-Docs/blob/main/reference/7.6/Microsoft.PowerShell.Core/About/about_Pwsh.md
- 5.
N. Freed and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies," RFC 2045, IETF, November 1996. https://www.rfc-editor.org/rfc/rfc2045.html
The most common cause is encoding: PowerShell strings are UTF-16LE by default, while Linux tools use UTF-8. Always use [System.Text.Encoding]::UTF8.GetBytes() before calling [Convert]::ToBase64String() to match cross-platform output.
Intentionally use UTF-16LE encoding for this use case: $bytes = [System.Text.Encoding]::Unicode.GetBytes($command) then [Convert]::ToBase64String($bytes). The -EncodedCommand parameter expects UTF-16LE, not UTF-8.
Yes, the [Convert]::ToBase64String([System.IO.File]::ReadAllBytes(path)) pattern works in both. Avoid Get-Content for binary files , use ReadAllBytes instead to prevent text encoding corruption.
No. [Convert]::ToBase64String() returns a single unbroken string by default. If you need 76-character line wrapping for MIME or PEM output, pass Base64FormattingOptions.InsertLineBreaks as the second argument.
Yes. EncodedCommand is Base64 transport, not protection. Anyone who can inspect the command line can decode it back to the original command. CapyToolkit follows the same transparent rule for checks: it runs locally and never uploads pasted values.
Base64 in curl and CLI Basic Auth
In curl scripts, Basic Auth is a header problem before it is a command-line problem.
curl handles HTTP Basic Auth natively with -u, and knowing the underlying Base64 encoding is essential for building headers manually in shell scripts.
HTTP Basic Authentication encodes credentials as Base64(username:password) and sends them in the Authorization header as "Basic base64 command on Linux and macOS produces this encoding directly. Understanding the pattern lets you build auth headers for APIs that expect manual header construction, debug authentication failures, and create reusable shell functions for CI/CD pipelines.
HTTP Basic Auth and the Authorization header
The HTTP Basic Auth spec (RFC 7617) defines the Authorization header value as "Basic " followed by Base64(username:password).1 The colon between username and password is a literal separator; the username itself cannot contain a colon, but the password can contain colons because the split happens on the first colon only.
Building the header value correctly
On the command line, echo -n 'user:password' | base64 produces the correct value.2 The -n flag is critical: without it, echo appends a newline character, which becomes part of the Base64 input and produces a different value. On macOS, echo -n is standard; on some systems use printf '%s' 'user:password' | base64 to guarantee no newline. This trailing newline mistake is one of the most common causes of intermittent authentication failures in shell scripts, because the encoded value changes every time the credential string length crosses a line-wrapping boundary and the extra newline character shifts the entire Base64 output.
Treating the credential as bytes before encoding also makes the mistake reproducible in isolation, so a quick decode of the produced value catches the stray newline before the request ever leaves the script. It also turns a flaky auth bug into a one-line local check you can run in a terminal rather than a round trip against a live API that logs the failure.
Using curl for Basic Auth
curl natively supports Basic Auth via -u 'username:password', which handles the Base64 encoding automatically and is the correct approach for interactive use on the command line. The -u flag always produces a standard Base64 encoding of the username colon password string, with no line wrapping or variant selection needed on your part.
When manual headers are still useful
For scripted use where you need to construct headers manually, perhaps to reuse the same token across multiple requests, log the header for debugging, or pass it to a non-curl tool, echo -n "$USER:$PASS" | base64 | tr -d '\n' produces the encoded value. Pipe through tr -d '\n' to strip the trailing newline that base64 adds at the end of its output. Then inject with curl -H "Authorization: Basic $TOKEN" https://api.example.com. Never hardcode credentials in scripts; read them from environment variables or a secrets manager. The manual header approach also matters when the username or password contains characters that curl's -u flag interprets specially, such as @ in email-style usernames, where the manual header avoids ambiguity about which part of the string is the credential versus the URL.
Cross-platform and CI/CD considerations
Linux and macOS ship different base64 implementations. GNU base64 (Linux) wraps output at 76 characters by default; add -w 0 to disable wrapping.3 BSD base64 (macOS) does not wrap by default. This platform difference means a script that produces clean single-line output on macOS may silently insert line breaks when run on a Linux CI runner, breaking downstream parsing.
Making CI output single-line
In CI/CD pipelines, always use -w 0 on Linux to ensure the output is a single unbroken line: echo -n "$USER:$PASS" | base64 -w 0. In Docker images, verify which variant is installed. For PowerShell pipelines, use [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("$USER:$PASS")) instead. Environment-based credential injection (CI secrets) is safer than constructing credentials inline , the value should flow from a secret store rather than being built in the pipeline definition. A practical cross-platform pattern is to pipe through tr -d '\n' after base64 on any platform, which strips both the trailing newline and any line-wrapping characters regardless of which base64 variant is installed, making the script portable without requiring platform detection.
Building reusable shell functions for API authentication
When you maintain a collection of shell scripts for API interactions, a dedicated helper function encapsulates the credential encoding and prevents the common mistake of calling echo without -n in a caller script. A reusable function: basic_auth_header() { printf 'Basic %s' "$(printf '%s:%s' "$1" "$2" | base64 -w 0)"; }. Callers invoke it as AUTH=$(basic_auth_header "$API_USER" "$API_PASS") and pass $AUTH to curl with -H "Authorization: $AUTH". Using printf '%s:%s' rather than string concatenation avoids shell interpretation of special characters in either the username or password value.
Store the function in a sourced file (source auth_helpers.sh) rather than copy-pasting it across multiple scripts. When credential format requirements change, such as switching from Basic Auth to Bearer tokens or adding a realm prefix, updating the function in one place propagates the fix to all call sites automatically. This pattern also keeps the encoding function close to the credential resolution logic, so any changes to how credentials are sourced are applied consistently across all scripts that consume the helper.
Debugging curl requests with verbose output
The -v flag on curl prints the full request and response headers, including the Authorization header your script constructed.4 Inspect the Authorization: Basic line in the output to confirm the encoded value looks correct, then decode it manually: echo 'dXNlcjpwYXNz' | base64 -d should return exactly user:pass with no trailing newline or extra whitespace.5
For HTTPS endpoints, -v also shows the TLS handshake details alongside the HTTP headers. If the server responds with WWW-Authenticate: Basic realm="..." in the 401 response, the realm value is informational and does not affect the credential encoding. A 401 response with no WWW-Authenticate header means the server rejected the request before evaluating the credential, often because the Authorization header was absent or structurally malformed. Use -v to print the raw byte stream of the entire request: this reveals invisible characters or incorrect line endings that look correct in the -v output but fail on the wire.
When to use this
Use CLI Base64 and curl Basic Auth when authenticating against REST APIs in shell scripts, building Authorization headers for CI/CD pipelines, debugging authentication issues, or constructing bearer tokens and API keys for testing without a full HTTP client library.
Notes
Use echo -n (not echo) to avoid newline corruption. On Linux, add -w 0 to base64 to suppress line breaks. For curl, -u 'user:pass' is simpler than manual header construction. Strip trailing newlines from base64 output with tr -d '\n' before embedding in headers.
Examples
Encode credentials
echo -n 'username:password' | base64 # dXNlcm5hbWU6cGFzc3dvcmQ=
curl with manual header
TOKEN=$(echo -n "$USER:$PASS" | base64 -w 0) curl -H "Authorization: Basic $TOKEN" https://api.example.com/resource
curl native auth
curl -u 'username:password' https://api.example.com/resource # Equivalent to the manual header above
Decode a token
echo 'dXNlcm5hbWU6cGFzc3dvcmQ=' | base64 -d # username:password
Verify with the Base64 Text & File Encoder/Decoder tool.
Encode credentials
echo -n 'username:password' | base64 # dXNlcm5hbWU6cGFzc3dvcmQ=
Code says: dXNlcm5hbWU6cGFzc3dvcmQ=
- 1.
J. Reschke, "The 'Basic' HTTP Authentication Scheme," RFC 7617, IETF, September 2015. https://www.rfc-editor.org/rfc/rfc7617
- 2.
"echo," POSIX.1-2017 (IEEE Std 1003.1-2017), The Open Group, 2018. https://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html
- 3.
"base64 invocation," GNU Coreutils Manual, GNU.org, accessed June 2026. https://www.gnu.org/software/coreutils/manual/html_node/base64-invocation.html
- 4.
Daniel Stenberg, "curl man page," curl.se, accessed June 2026. https://curl.se/docs/manpage.html
- 5.
S. Josefsson, "The Base16, Base32, and Base64 Data Encodings," RFC 4648, IETF, October 2006. https://www.rfc-editor.org/rfc/rfc4648
echo appends a newline character by default. That newline becomes part of the input, so the Base64 output encodes "username:password\n" rather than "username:password". The resulting header value does not match what the server expects. Always use echo -n or printf.
They produce identical HTTP requests. -u is more convenient for interactive use and handles special characters automatically. Manual header construction is useful when you need to reuse the token, log it for debugging, or pass it to a tool other than curl.
GNU base64 (Linux) wraps output at 76 characters by default. BSD base64 (macOS) outputs a single line. Add -w 0 on Linux to disable wrapping. In CI/CD pipelines, always use -w 0 to ensure consistent output.
Yes. With -u, curl handles special characters correctly. With manual header construction, use printf '%s:%s' "$USER" "$PASS" | base64 rather than building the string with concatenation, which can break if the password contains shell metacharacters.
Only over HTTPS. Over plain HTTP, the Base64-encoded credentials are visible to anyone on the network. Base64 is not encryption; it is trivially reversible. Always use HTTPS (TLS) with Basic Auth, and prefer modern alternatives like OAuth tokens or API keys where possible. CapyToolkit can help inspect encoded test values locally, but it does not send credentials to any server.