The java.util.Base64 API (JDK 8+) Mental Model
Before JDK 8 (2014), Java Base64 was a mess — sun.misc.BASE64Encoder was internal and unreliable, and most projects pulled in Apache Commons Codec. Since JDK 8,java.util.Base64 gives you three thread-safe encoder factories plus streaming via wrap(). That's all you need — Commons Codec Base64 is no longer required.
The three encoder types:
Base64.getEncoder()— RFC 4648 §4 (standard alphabet with+and/, includes padding). For general use, HTTP Basic Auth, MIME data URLs.Base64.getUrlEncoder()— RFC 4648 §5 (uses-and_, includes padding). For URL query strings, filenames.Base64.getMimeEncoder()— RFC 2045 (inserts CRLF every 76 chars). For email bodies. Rarely needed in modern code.
All three have a .withoutPadding() variant. Chain it for JWT-style output.
Encoding a String — The Standard Pattern
import java.util.Base64;
import java.nio.charset.StandardCharsets;
public class Base64Example {
public static void main(String[] args) {
String text = "Hello 世界 👋";
// Step 1: String → byte[] (always specify charset)
byte[] utf8Bytes = text.getBytes(StandardCharsets.UTF_8);
// Step 2: byte[] → Base64 String
String encoded = Base64.getEncoder().encodeToString(utf8Bytes);
System.out.println(encoded);
// SGVsbG8g5LiW55WMIPCfkYs=
// One-liner:
String result = Base64.getEncoder()
.encodeToString(text.getBytes(StandardCharsets.UTF_8));
System.out.println(result);
}
}Encoding a File
import java.io.*;
import java.nio.file.*;
import java.util.Base64;
public class FileBase64 {
// Small to medium files — read all at once
public static String encodeSmallFile(Path path) throws IOException {
byte[] data = Files.readAllBytes(path);
return Base64.getEncoder().encodeToString(data);
}
// Large files — streaming (does not load the file into memory)
public static void encodeStreamingFile(Path in, Path out) throws IOException {
try (InputStream input = Files.newInputStream(in);
OutputStream output = Files.newOutputStream(out);
OutputStream base64Out = Base64.getEncoder().wrap(output)) {
byte[] buf = new byte[8192];
int n;
while ((n = input.read(buf)) > 0) {
base64Out.write(buf, 0, n);
}
// try-with-resources calls close(), which flushes the encoder's
// internal buffer and writes final padding. Do not skip this.
}
}
// Data URL for embedding an image in HTML
public static String imageDataUrl(Path imagePath, String mimeType) throws IOException {
byte[] data = Files.readAllBytes(imagePath);
String b64 = Base64.getEncoder().encodeToString(data);
return "data:" + mimeType + ";base64," + b64;
}
}URL-Safe Base64 and JWT-Style Encoding
import java.util.Base64;
import java.nio.charset.StandardCharsets;
public class JwtStyleBase64 {
public static void main(String[] args) {
String payload = "{\"user_id\":42,\"role\":\"admin\"}";
byte[] bytes = payload.getBytes(StandardCharsets.UTF_8);
// Standard Base64 (uses + and /)
String std = Base64.getEncoder().encodeToString(bytes);
System.out.println(std); // eyJ1c2...uIn0=
// URL-safe Base64 (uses - and _)
String urlsafe = Base64.getUrlEncoder().encodeToString(bytes);
System.out.println(urlsafe); // eyJ1c2...uIn0=
// JWT-style: URL-safe + no padding
String jwt = Base64.getUrlEncoder()
.withoutPadding()
.encodeToString(bytes);
System.out.println(jwt); // eyJ1c2...uIn0
// Decoding — Base64.Decoder auto-handles padding-less input
byte[] decoded = Base64.getUrlDecoder().decode(jwt);
System.out.println(new String(decoded, StandardCharsets.UTF_8));
}
}Encoding an Object via JSON (Jackson)
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Base64;
import java.nio.charset.StandardCharsets;
record User(int id, String email, java.util.List<String> roles, String joined) {}
public class ObjectBase64 {
private static final ObjectMapper MAPPER = new ObjectMapper();
public static String encodeUser(User u) throws Exception {
String json = MAPPER.writeValueAsString(u);
return Base64.getEncoder()
.encodeToString(json.getBytes(StandardCharsets.UTF_8));
}
public static User decodeUser(String encoded) throws Exception {
byte[] bytes = Base64.getDecoder().decode(encoded);
String json = new String(bytes, StandardCharsets.UTF_8);
return MAPPER.readValue(json, User.class);
}
public static void main(String[] args) throws Exception {
User user = new User(42, "[email protected]",
java.util.List.of("admin", "editor"), "2026-01-15");
String encoded = encodeUser(user);
System.out.println(encoded);
User decoded = decodeUser(encoded);
System.out.println(decoded);
}
}Building an HTTP Basic Auth Header in Java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class BasicAuthExample {
public static String basicAuthHeader(String user, String password) {
String creds = user + ":" + password;
String token = Base64.getEncoder()
.encodeToString(creds.getBytes(StandardCharsets.UTF_8));
return "Basic " + token;
}
public static HttpResponse<String> callProtected() throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/protected"))
.header("Authorization", basicAuthHeader("admin", "secret123"))
.GET()
.build();
return HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
}
}Common Pitfalls in Java Base64 Code
- Using
getBytes()without a charset— The no-arg version uses the JVM's default charset which varies between OSes (UTF-8 on Linux/macOS, windows-1252 on some Windows setups). Always passStandardCharsets.UTF_8explicitly for consistent output across environments. - Skipping
close()on wrap() streams —Base64.getEncoder().wrap(out)buffers up to 3 bytes internally. Without closing (or via try-with-resources), those bytes are lost and the last few characters of the output are missing. - Using
getMimeEncoder()when you want a single line — MIME encoder inserts CRLF every 76 chars. That breaks JSON. Default togetEncoder()unless you're specifically writing a MIME email body. - Still using
DatatypeConverter.printBase64Binary()— this was removed from Java 11 (moved tojakarta.xml.bind). Usejava.util.Base64instead. - Assuming
sun.misc.BASE64Encoderis available — Removed in JDK 9. Any code still using it fails at runtime. Migrate tojava.util.Base64.
Command Line Alternative
For quick tests without writing a full class, use jshell (JDK 9+ REPL):
# Start jshell
jshell
# Inside jshell:
import java.util.Base64;
import java.nio.charset.StandardCharsets;
Base64.getEncoder().encodeToString("Hello".getBytes(StandardCharsets.UTF_8))
// $1 ==> "SGVsbG8="
# Or a compact one-liner via shell:
jshell -s <<< 'System.out.println(java.util.Base64.getEncoder().encodeToString("Hello".getBytes()));'Key Facts
- Package:
- java.util.Base64 (JDK 8+, no external dependency)
- Standard encoder:
- Base64.getEncoder().encodeToString(bytes)
- URL-safe encoder:
- Base64.getUrlEncoder().encodeToString(bytes)
- JWT-style encoder:
- Base64.getUrlEncoder().withoutPadding().encodeToString(bytes)
- Streaming:
- Base64.getEncoder().wrap(outputStream) — must be closed to flush
- Input type:
- byte[] (use .getBytes(StandardCharsets.UTF_8) on strings)
- Thread safety:
- Encoder/Decoder instances are stateless — safe to share
Related Base64 Tools
- Base64 Encode Online — general-purpose browser encoder
- Base64 Encode in Python — Python 3 equivalent
- Base64 Encode in JavaScript — Node.js and browser
- Base64 Encode in PHP — PHP base64_encode
- URL-Safe Base64 — cross-language URL encoding guide
- Base64 Decode Online — reverse the encoding
- JWT Debugger — inspect JWT tokens