Codificación Base64 en Java — java.util.Base64

·Java Security & API Engineer·Revisado porPavel Novak·Publicado

Usa el Codificador Base64 Online gratuito directamente en tu navegador — sin instalación.

Probar Codificador Base64 Online online →

Cada vez que configuro un encabezado HTTP Basic Auth, inserto un certificado en un secreto de Kubernetes o envío datos binarios a través de una API JSON, el primer paso es siempre el mismo: codificar en Base64 los bytes en bruto para obtener una cadena segura en ASCII. Java facilita esto con java.util.Base64, la API estándar disponible desde Java 8 que reemplazó al deprecado sun.misc.BASE64Encoder. Para una codificación rápida sin escribir código, el Codificador Base64 de ToolDeck lo resuelve al instante en el navegador. Esta guía cubre Base64.getEncoder(), getUrlEncoder(), getMimeEncoder(), codificación de archivos, streaming con wrap(OutputStream), y los errores que afectan incluso a desarrolladores Java con experiencia. Todos los ejemplos compilan en Java 8 hasta Java 21+.

  • Base64.getEncoder().encodeToString(bytes) es el one-liner estándar — incluido en el JDK desde Java 8, sin cambios en Java 17 y 21.
  • Pasa siempre StandardCharsets.UTF_8 a String.getBytes() antes de codificar — omitirlo usa el predeterminado de la plataforma, que varía entre JVMs.
  • getUrlEncoder() produce salida URL-safe (- en lugar de +, _ en lugar de /) y withoutPadding() elimina los caracteres = del final.
  • getMimeEncoder() inserta saltos de línea cada 76 caracteres — requerido por los formatos de correo (MIME) y certificados PEM.
  • Para archivos grandes, usa Base64.getEncoder().wrap(OutputStream) para transmitir sin cargar el archivo completo en memoria.

¿Qué es la codificación Base64?

Base64 convierte datos binarios arbitrarios en una cadena compuesta por 64 caracteres ASCII imprimibles: A-Z, a-z, 0-9, +, y /. Cada 3 bytes de entrada producen exactamente 4 caracteres Base64. Si la longitud de la entrada no es múltiplo de 3, se añaden uno o dos caracteres de relleno =. La salida codificada es siempre aproximadamente un 33% más grande que los datos originales.

Base64 no es cifrado. Cualquier persona con la cadena codificada puede decodificarla. Su propósito es la seguridad en el transporte: los encabezados HTTP, los payloads JSON, los documentos XML y el cuerpo de los correos electrónicos son protocolos de texto que no pueden transportar bytes binarios en bruto sin corrupción. Los casos de uso comunes en Java incluyen HTTP Basic Authentication, incrustar certificados PEM, almacenar datos binarios en columnas de texto de bases de datos y construir segmentos de tokens JWT.

Before · text
After · text
deploy-svc:sk_live_4eC39HqLyjWDarjtT1zdp7dc
ZGVwbG95LXN2Yzpza19saXZlXzRlQzM5SHFMeWpXRGFyanRUMXpkcDdkYw==

Base64.getEncoder().encodeToString() — La API estándar

java.util.Base64 se introdujo en Java 8 como el reemplazo oficial de sun.misc.BASE64Encoder. La clase proporciona tres métodos de fábrica estáticos — cada uno devuelve una instancia de la clase anidada Base64.Encoder — que cubren las tres variantes de Base64 definidas en el RFC 4648. No se necesita ninguna librería de terceros. Sin dependencia Maven. Solo importa y llama.

Ejemplo mínimo — Codificar un String

Java 8+
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class EncodeDemo {
    public static void main(String[] args) {
        String credentials = "monitoring-svc:9f2a7c4e-b1d8-4a3f";
        byte[] credentialBytes = credentials.getBytes(StandardCharsets.UTF_8);

        String encoded = Base64.getEncoder().encodeToString(credentialBytes);
        System.out.println(encoded);
        // bW9uaXRvcmluZy1zdmM6OWYyYTdjNGUtYjFkOC00YTNm
    }
}

El paso clave que la mayoría de desarrolladores Java pasan por alto la primera vez: un String debe convertirse a byte[] antes de codificar. Base64 opera sobre bytes, no sobre caracteres. encodeToString() acepta un byte[] y devuelve el String Base64 directamente. Si necesitas el resultado codificado como bytes en lugar de un String, usa encode(byte[]) — devuelve un byte[] de los caracteres Base64 codificados en ASCII, útil cuando escribes directamente en un OutputStream o construyes tramas de protocolo binario.

HTTP Basic Auth — El caso de uso más común

HTTP Basic Authentication es probablemente la razón más habitual por la que los desarrolladores Java recurren a la codificación Base64. La especificación (RFC 7617) requiere que la cadena de credenciales username:password esté codificada en Base64 y colocada en el encabezado Authorization. He visto esto hacerse mal más veces de las que puedo contar — normalmente por olvidar el separador de dos puntos o por codificar los componentes por separado.

Java — encabezado HTTP Basic Auth
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class BasicAuthExample {
    public static void main(String[] args) throws Exception {
        String username = "metrics-exporter";
        String apiKey = "sk_live_4eC39HqLyjWDarjtT1zdp7dc";

        // username:password → Base64
        String credentials = username + ":" + apiKey;
        String authHeader = "Basic " + Base64.getEncoder()
            .encodeToString(credentials.getBytes(StandardCharsets.UTF_8));

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.example.com/v2/metrics"))
            .header("Authorization", authHeader)
            .build();

        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());

        System.out.println(response.statusCode());  // 200
    }
}

Ciclo completo — Codificar y decodificar

Java 8+ — ciclo completo de codificación y decodificación
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class RoundTrip {
    public static void main(String[] args) {
        String original = "X-Correlation-ID: req_8a4f2c91-e7b3-4d56-9012-3f7a8b9c0d1e";

        // Codificar
        String encoded = Base64.getEncoder()
            .encodeToString(original.getBytes(StandardCharsets.UTF_8));
        System.out.println(encoded);
        // WC1Db3JyZWxhdGlvbi1JRDogcmVxXzhhNGYyYzkxLWU3YjMtNGQ1Ni05MDEyLTNmN2E4YjljMGQxZQ==

        // Decodificar
        byte[] decodedBytes = Base64.getDecoder().decode(encoded);
        String decoded = new String(decodedBytes, StandardCharsets.UTF_8);

        System.out.println(original.equals(decoded));  // true
    }
}
Nota:La API java.util.Base64 es idéntica desde Java 8 hasta Java 17 y Java 21. No se necesita ninguna migración al actualizar el JDK. El mismo código compila y se ejecuta en cualquier versión desde Java 8.

Codificación de datos que no son String — byte[], UUID y marcas de tiempo

La codificación Base64 en Java siempre comienza con un byte[]. Los Strings se convierten mediante getBytes(StandardCharsets.UTF_8), pero otros tipos necesitan un paso de conversión previo. Los UUIDs, marcas de tiempo e identificadores numéricos deben serializarse a una representación de string o bytes antes de poder codificarlos en Base64.

UUID — Codificar como representación en String

Java — codificación Base64 de un UUID
import java.util.Base64;
import java.util.UUID;
import java.nio.charset.StandardCharsets;

UUID sessionId = UUID.fromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
String encoded = Base64.getEncoder()
    .encodeToString(sessionId.toString().getBytes(StandardCharsets.UTF_8));
System.out.println(encoded);
// NmJhN2I4MTAtOWRhZC0xMWQxLTgwYjQtMDBjMDRmZDQzMGM4

UUID compacto — Codificar los 16 bytes en bruto

Si quieres un resultado codificado más corto, extrae los 128 bits del UUID como 16 bytes en bruto en lugar de convertirlo a su forma de string de 36 caracteres. La salida Base64 pasa de 48 caracteres a 24.

Java — codificación compacta de UUID
import java.nio.ByteBuffer;
import java.util.Base64;
import java.util.UUID;

UUID eventId = UUID.fromString("550e8400-e29b-41d4-a716-446655440000");

ByteBuffer buffer = ByteBuffer.wrap(new byte[16]);
buffer.putLong(eventId.getMostSignificantBits());
buffer.putLong(eventId.getLeastSignificantBits());

String compact = Base64.getUrlEncoder()
    .withoutPadding()
    .encodeToString(buffer.array());
System.out.println(compact);
// VQ6EAOKbQdSnFkRmVUQAAA
// 22 caracteres frente a 48 del enfoque basado en string

Marca de tiempo y payload mixto

Java — codificación de un payload similar a JSON con marca de tiempo
import java.time.Instant;
import java.util.Base64;
import java.nio.charset.StandardCharsets;

// Simulando un payload estilo JWT
String payload = String.format(
    "{"sub":"usr_7b3c","iss":"auth.internal","iat":%d,"exp":%d}",
    Instant.now().getEpochSecond(),
    Instant.now().plusSeconds(3600).getEpochSecond()
);

String encoded = Base64.getUrlEncoder()
    .withoutPadding()
    .encodeToString(payload.getBytes(StandardCharsets.UTF_8));
System.out.println(encoded);
// eyJzdWIiOiJ1c3JfN2IzYyIsImlzcyI6ImF1dGguaW50ZXJuYWwiLCJpYXQiOj... (URL-safe, sin relleno)
Advertencia:No llames a toString() sobre un byte[] esperando obtener su contenido — eso te da el hash de identidad del arreglo, como [B@6d06d69c. Usa new String(bytes, StandardCharsets.UTF_8) o pasa el arreglo de bytes directamente a encodeToString().

Referencia de métodos de Base64.Encoder

La clase java.util.Base64 expone tres métodos de fábrica, cada uno devuelve una instancia de Base64.Encoder configurada para una variante específica. Las instancias del codificador son thread-safe y sin estado — créalas una vez y reutilízalas.

Método
Tipo
Descripción
getEncoder()
Base64.Encoder
Devuelve un codificador básico RFC 4648 con el alfabeto estándar (A-Z, a-z, 0-9, +, /)
getUrlEncoder()
Base64.Encoder
Devuelve un codificador con el alfabeto URL-safe (- en lugar de +, _ en lugar de /)
getMimeEncoder()
Base64.Encoder
Devuelve un codificador MIME que inserta saltos de línea \r\n cada 76 caracteres
getMimeEncoder(lineLength, lineSeparator)
Base64.Encoder
Codificador MIME con longitud de línea y separador de bytes personalizados
encoder.withoutPadding()
Base64.Encoder
Devuelve un codificador que omite los caracteres de relleno = al final
encoder.encode(byte[])
byte[]
Codifica un arreglo de bytes y devuelve el arreglo de bytes codificado
encoder.encodeToString(byte[])
String
Codifica un arreglo de bytes y devuelve directamente un String codificado
encoder.wrap(OutputStream)
OutputStream
Envuelve un OutputStream para codificación Base64 en modo streaming

Base64.getUrlEncoder() — Codificación URL-Safe

El codificador URL-safe usa un alfabeto alternativo donde + se convierte en - y / se convierte en _, tal como se define en la sección 5 del RFC 4648. Esto importa cuando el string Base64 aparece en un parámetro de consulta de URL, un nombre de archivo o un valor de cookie — los caracteres del Base64 estándar entran en conflicto con los delimitadores de URL y los caracteres reservados del sistema de archivos.

Java — codificación Base64 URL-safe
import java.util.Base64;
import java.nio.charset.StandardCharsets;

String redirectUri = "https://app.internal/callback?state=auth_pending&nonce=9f2a7c";
byte[] data = redirectUri.getBytes(StandardCharsets.UTF_8);

// Codificador estándar — contiene + y / que rompen las URLs
String standard = Base64.getEncoder().encodeToString(data);
System.out.println(standard);
// aHR0cHM6Ly9hcHAuaW50ZXJuYWwvY2FsbGJhY2s/c3RhdGU9YXV0aF9wZW5kaW5nJm5vbmNlPTlmMmE3Yw==

// Codificador URL-safe — seguro para parámetros de consulta y nombres de archivo
String urlSafe = Base64.getUrlEncoder().encodeToString(data);
System.out.println(urlSafe);
// aHR0cHM6Ly9hcHAuaW50ZXJuYWwvY2FsbGJhY2s_c3RhdGU9YXV0aF9wZW5kaW5nJm5vbmNlPTlmMmE3Yw==

// URL-safe sin relleno — para JWTs y tokens compactos
String noPadding = Base64.getUrlEncoder().withoutPadding().encodeToString(data);
System.out.println(noPadding);
// aHR0cHM6Ly9hcHAuaW50ZXJuYWwvY2FsbGJhY2s_c3RhdGU9YXV0aF9wZW5kaW5nJm5vbmNlPTlmMmE3Yw

La variante withoutPadding() elimina los caracteres de relleno = del final. Las especificaciones JWT requieren Base64 URL-safe sin relleno para los segmentos de encabezado y payload, así que getUrlEncoder().withoutPadding() es exactamente la llamada que necesitas cuando construyes o manipulas tokens JWT manualmente.

Nota:El método withoutPadding() devuelve una nueva instancia de codificador — no modifica el original. Ambos pueden asignarse a campos static final y reutilizarse de forma segura entre hilos.

Codificar desde archivo y respuesta de API

Los dos escenarios más comunes en el mundo real para la codificación Base64 en Java: leer un archivo binario del disco (certificados, imágenes, paquetes de configuración) y codificar datos recibidos de una respuesta HTTP.

Codificar un archivo en Base64

Java — codificación de un archivo
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;

public class FileEncoder {
    public static void main(String[] args) {
        try {
            byte[] fileBytes = Files.readAllBytes(Path.of("certs/server.pem"));
            String encoded = Base64.getEncoder().encodeToString(fileBytes);

            System.out.printf("Original: %d bytes%n", fileBytes.length);
            System.out.printf("Codificado:  %d chars%n", encoded.length());

            // Escribir el contenido codificado en un archivo de texto
            Files.writeString(
                Path.of("certs/server.pem.b64"),
                encoded
            );
        } catch (java.io.IOException e) {
            System.err.println("Error al leer el archivo: " + e.getMessage());
        }
    }
}

Codificar el cuerpo de una respuesta de API

Java 11+ — codificación de una respuesta HTTP
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Base64;

public class ApiEncoder {
    public static void main(String[] args) {
        try {
            HttpClient client = HttpClient.newHttpClient();
            HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.example.com/v2/reports/weekly.pdf"))
                .header("Authorization", "Bearer tok_8f2a9c3d")
                .build();

            HttpResponse<byte[]> response = client.send(
                request, HttpResponse.BodyHandlers.ofByteArray()
            );

            if (response.statusCode() == 200) {
                String encoded = Base64.getEncoder()
                    .encodeToString(response.body());
                System.out.printf("Codificados %d bytes → %d chars%n",
                    response.body().length, encoded.length());
            } else {
                System.err.printf("HTTP %d: %s%n",
                    response.statusCode(),
                    new String(response.body()));
            }
        } catch (Exception e) {
            System.err.println("La petición falló: " + e.getMessage());
        }
    }
}

Una nota rápida antes de la sección de línea de comandos: si solo necesitas pegar un archivo o una respuesta de API y obtener la salida Base64 sin escribir código, el Codificador Base64 online maneja tanto entradas de texto como binarias.

Codificación Base64 desde la línea de comandos

A veces solo necesitas codificar un string o un archivo desde la terminal — sin proyecto Java, sin IDE, sin paso de compilación. La mayoría de sistemas Unix incluyen el comando base64, y si tienes el JDK instalado, puedes usar jshell para un enfoque nativo de Java.

Bash — codificación Base64 desde la línea de comandos
# macOS / Linux — codificar un string
echo -n "deploy-bot:sk_prod_9f2a7c4e" | base64
# ZGVwbG95LWJvdDpza19wcm9kXzlmMmE3YzRl

# Codificar un archivo
base64 < certs/server.pem > certs/server.pem.b64

# Usando jshell (JDK 9+)
echo 'System.out.println(java.util.Base64.getEncoder().encodeToString("deploy-bot:sk_prod_9f2a7c4e".getBytes()))' | jshell -

# Usando java directamente con un one-liner
java -e 'System.out.println(java.util.Base64.getEncoder().encodeToString(args[0].getBytes()))' "my-secret"
# Nota: java -e requiere JDK 23+ (JEP 477)

El enfoque con jshell es especialmente útil cuando necesitas verificar que tu código Java produce la misma salida que una herramienta Unix, o cuando depuras una discrepancia entre lo que envía tu servicio y lo que espera el receptor. Tengo un alias de shell para eso.

Nota:En macOS, el comando base64 usa -D para decodificar. En Linux (GNU coreutils) usa -d. El comportamiento de codificación es idéntico en ambos. El indicador -w 0 en Linux deshabilita el ajuste de línea en la salida, que es lo que normalmente quieres al redirigir a otros comandos.

Apache Commons Codec — Alternativa de alto rendimiento

Para la mayoría de aplicaciones, java.util.Base64 es suficientemente rápido. Pero si procesas millones de operaciones de codificación en un bucle ajustado — como pipelines de ingesta de logs o brokers de mensajes de alto rendimiento — vale la pena comparar con Apache Commons Codec. Existe desde mucho antes de Java 8 y ofrece una alternativa sólida con una superficie de API algo diferente.

Java — Apache Commons Codec
// Maven: org.apache.commons:commons-codec:1.17.0
import org.apache.commons.codec.binary.Base64;
import java.nio.charset.StandardCharsets;

byte[] telemetryPayload = ("{"service":"metrics-collector","
    + ""host":"prod-east-07","
    + ""cpu_pct":72.4,"
    + ""mem_mb":3891,"
    + ""timestamp":1710523200}")
    .getBytes(StandardCharsets.UTF_8);

// Codificación estándar
String encoded = Base64.encodeBase64String(telemetryPayload);

// Codificación URL-safe
String urlSafe = Base64.encodeBase64URLSafeString(telemetryPayload);

// Comprobar si un string es Base64 válido
boolean valid = Base64.isBase64(encoded);
System.out.println(valid);  // true

Apache Commons Codec también proporciona Base64OutputStream y Base64InputStream para escenarios de streaming, e incluye un método de validación que el codificador del JDK no tiene. Si Commons Codec ya está en tu árbol de dependencias (viene incluido en muchos proyectos Apache), no hay ninguna razón para no usarlo.

Guava BaseEncoding

La librería Guava de Google incluye BaseEncoding, que proporciona una API fluida para Base64 con separadores de línea configurables, control de relleno y soporte para los alfabetos estándar y URL-safe. La API es muy legible, pero añadir Guava (aproximadamente 3 MB) solo para la codificación Base64 es excesivo. Si Guava ya está en tu proyecto por sus utilidades de colecciones o caché, la API de codificación es un buen complemento.

Java — Guava BaseEncoding
// Maven: com.google.guava:guava:33.1.0-jre
import com.google.common.io.BaseEncoding;
import java.nio.charset.StandardCharsets;

byte[] webhookPayload = ("{"event":"deployment.completed","
    + ""repo":"payments-api","
    + ""sha":"a7f2c91e4b3d","
    + ""environment":"production"}")
    .getBytes(StandardCharsets.UTF_8);

// Base64 estándar
String standard = BaseEncoding.base64().encode(webhookPayload);

// URL-safe
String urlSafe = BaseEncoding.base64Url().encode(webhookPayload);

// Sin relleno
String noPad = BaseEncoding.base64Url().omitPadding().encode(webhookPayload);

// Con separadores de línea (estilo PEM)
String wrapped = BaseEncoding.base64()
    .withSeparator("\n", 64)
    .encode(webhookPayload);

Base64.getMimeEncoder() — Salida MIME y PEM con saltos de línea

El codificador MIME inserta saltos de línea \r\n cada 76 caracteres, siguiendo la especificación MIME (RFC 2045). Los certificados PEM, los adjuntos de correo S/MIME y algunas APIs heredadas esperan este formato. Los codificadores estándar y URL-safe producen una sola línea sin interrupciones — si pasas su salida a un sistema que espera Base64 con saltos de línea, puede fallar silenciosamente o rechazar los datos.

Java — codificación Base64 MIME
import java.util.Base64;
import java.nio.charset.StandardCharsets;

// Simular el cuerpo de un certificado PEM
byte[] certData = new byte[256];  // En la práctica, leer desde un archivo .der
new java.security.SecureRandom().nextBytes(certData);

// Codificador MIME predeterminado — 76 chars por línea, separador \r\n
String mimeEncoded = Base64.getMimeEncoder().encodeToString(certData);
System.out.println(mimeEncoded);
// QYx2K3p8Xg7JmN1R+wFkLd...  (76 chars)
// Ht5Bv9CzAq0PnSjYl8WxUe...  (76 chars)
// ...

// Codificador MIME personalizado — 64 chars por línea (estándar PEM), separador \n
Base64.Encoder pemEncoder = Base64.getMimeEncoder(64, new byte[]{'\n'});
String pemBody = pemEncoder.encodeToString(certData);
System.out.println("-----BEGIN CERTIFICATE-----");
System.out.println(pemBody);
System.out.println("-----END CERTIFICATE-----");
Advertencia:No uses getMimeEncoder() para tokens JWT, encabezados HTTP ni parámetros de URL. Los saltos de línea corromperán los datos en esos contextos. Usa getEncoder() o getUrlEncoder() en su lugar.

Archivos grandes con streaming usando Base64.getEncoder().wrap()

Cargar un archivo completo en un byte[] con Files.readAllBytes() funciona para archivos pequeños, pero para archivos de más de 50-100 MB arriesgas un OutOfMemoryError. El JDK ofrece Base64.getEncoder().wrap(OutputStream), que devuelve un OutputStream que codifica los datos al vuelo mientras escribes en él. Los bytes codificados fluyen hacia el stream subyacente sin almacenar toda la entrada en memoria.

Java — codificación Base64 en streaming
import java.io.*;
import java.nio.file.*;
import java.util.Base64;

public class StreamingEncoder {
    public static void main(String[] args) throws IOException {
        Path inputPath = Path.of("backups/database-export.sql.gz");
        Path outputPath = Path.of("backups/database-export.sql.gz.b64");

        try (
            InputStream in = Files.newInputStream(inputPath);
            OutputStream fileOut = Files.newOutputStream(outputPath);
            OutputStream base64Out = Base64.getEncoder().wrap(fileOut)
        ) {
            byte[] buffer = new byte[8192];
            int bytesRead;
            long totalBytes = 0;

            while ((bytesRead = in.read(buffer)) != -1) {
                base64Out.write(buffer, 0, bytesRead);
                totalBytes += bytesRead;
            }

            System.out.printf("Transmitidos %d bytes a través del codificador Base64%n", totalBytes);
        }
        // Cerrar base64Out vacía automáticamente los bytes de relleno finales
    }
}

El bloque try-with-resources gestiona el vaciado y cierre. Un detalle que sorprende a muchos: el relleno Base64 final solo se escribe cuando se cierra el OutputStream envolvente. Si olvidas cerrarlo (o solo cierras el stream externo), los últimos caracteres de tu salida codificada pueden estar incompletos.

Streaming a un socket de red

El método wrap() funciona con cualquier OutputStream — salida de archivo, salida de socket, cuerpo de respuesta HTTP, incluso ByteArrayOutputStream. A continuación un ejemplo que escribe datos codificados en Base64 directamente en un buffer en memoria, útil para pruebas unitarias o para construir payloads que se enviarán por HTTP:

Java — streaming a ByteArrayOutputStream
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.Base64;
import java.nio.charset.StandardCharsets;

ByteArrayOutputStream buffer = new ByteArrayOutputStream();

try (OutputStream encoder = Base64.getEncoder().wrap(buffer)) {
    // Escribir datos en trozos — simula la lectura desde un stream
    encoder.write("chunk-1:telemetry-data-".getBytes(StandardCharsets.UTF_8));
    encoder.write("chunk-2:more-payload-".getBytes(StandardCharsets.UTF_8));
    encoder.write("chunk-3:final-segment".getBytes(StandardCharsets.UTF_8));
}

String encoded = buffer.toString(StandardCharsets.UTF_8);
System.out.println(encoded);
// Y2h1bmstMTp0ZWxlbWV0cnktZGF0YS1jaHVuay0yOm1vcmUtcGF5bG9hZC1jaHVuay0zOmZpbmFsLXNlZ21lbnQ=

// Verificar el ciclo completo
byte[] decoded = Base64.getDecoder().decode(encoded);
System.out.println(new String(decoded, StandardCharsets.UTF_8));
// chunk-1:telemetry-data-chunk-2:more-payload-chunk-3:final-segment
Nota:El tamaño del buffer en el ejemplo de streaming (8192 bytes) no es arbitrario. Coincide con el tamaño de buffer predeterminado usado por BufferedInputStream y es un buen equilibrio entre uso de memoria y sobrecarga de llamadas al sistema. Buffers más pequeños aumentan el número de llamadas de lectura/escritura; buffers más grandes desperdician memoria sin mejora significativa en el rendimiento.

Instancias de codificador thread-safe — Almacena y reutiliza

El Base64.Encoder devuelto por los métodos de fábrica es inmutable y thread-safe. Llamar a Base64.getEncoder() en cada operación de codificación crea un nuevo objeto cada vez. La JVM probablemente lo optimice, pero almacenar el codificador en un campo static final deja clara la intención y evita asignaciones innecesarias en rutas críticas.

Java — instancias de codificador reutilizables
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class TokenService {
    // Crear una vez, reutilizar en todas partes — thread-safe
    private static final Base64.Encoder STANDARD = Base64.getEncoder();
    private static final Base64.Encoder URL_SAFE = Base64.getUrlEncoder().withoutPadding();
    private static final Base64.Encoder MIME = Base64.getMimeEncoder();

    public static String encodeForHeader(String value) {
        return STANDARD.encodeToString(value.getBytes(StandardCharsets.UTF_8));
    }

    public static String encodeForUrl(byte[] data) {
        return URL_SAFE.encodeToString(data);
    }

    public static String encodeForEmail(byte[] attachment) {
        return MIME.encodeToString(attachment);
    }
}

Este patrón es especialmente útil en servicios Spring Boot donde una clase de utilidades gestiona la codificación en múltiples controladores o métodos de servicio. La llamada a withoutPadding() devuelve una nueva instancia de codificador, por lo que puedes almacenar las variantes con y sin relleno como campos separados. Cada llamada a encodeToString() o encode() es sin estado — no se necesita sincronización, no hay estado mutable compartido.

Errores comunes

Llamar a getBytes() sin especificar un charset

Problema: String.getBytes() sin argumento de charset usa la codificación predeterminada de la plataforma, que es windows-1252 en Windows, UTF-8 en la mayoría de sistemas Linux, y varía en macOS. El mismo código produce salidas Base64 distintas en máquinas diferentes.

Solución: Pasa siempre StandardCharsets.UTF_8 de forma explícita.

Before · Java
After · Java
String text = "Ключ доступа: prod-east";
byte[] bytes = text.getBytes();  // predeterminado de la plataforma — impredecible
String encoded = Base64.getEncoder().encodeToString(bytes);
String text = "Ключ доступа: prod-east";
byte[] bytes = text.getBytes(StandardCharsets.UTF_8);
String encoded = Base64.getEncoder().encodeToString(bytes);
Usar el codificador estándar para parámetros de URL

Problema: Base64.getEncoder() produce los caracteres + y /. Cuando se colocan en una cadena de consulta de URL, + se interpreta como un espacio y / como un separador de ruta, corrompiendo silenciosamente el valor en el receptor.

Solución: Usa Base64.getUrlEncoder() para cualquier valor que vaya a aparecer en una URL.

Before · Java
After · Java
// Token en parámetro de consulta URL — fallará
String token = Base64.getEncoder()
    .encodeToString(sessionData);
String url = "https://auth.internal/verify?token=" + token;
// Codificación URL-safe — sin caracteres + ni /
String token = Base64.getUrlEncoder()
    .withoutPadding()
    .encodeToString(sessionData);
String url = "https://auth.internal/verify?token=" + token;
Decodificar con la variante de codificador incorrecta

Problema: Codificar con getUrlEncoder() y decodificar con getDecoder() (o viceversa) lanza IllegalArgumentException porque - y _ no son válidos en el alfabeto Base64 estándar, y + y / no son válidos en el alfabeto URL-safe.

Solución: Decodifica siempre con el decodificador correspondiente: getUrlDecoder() para URL-safe, getDecoder() para estándar.

Before · Java
After · Java
String encoded = Base64.getUrlEncoder()
    .encodeToString(data);
// Más tarde...
byte[] decoded = Base64.getDecoder()  // decodificador INCORRECTO
    .decode(encoded);
// IllegalArgumentException si encoded contiene - o _
String encoded = Base64.getUrlEncoder()
    .encodeToString(data);
// Más tarde...
byte[] decoded = Base64.getUrlDecoder()  // decodificador correcto
    .decode(encoded);
No cerrar el OutputStream de wrap()

Problema: El codificador en streaming almacena en buffer hasta 2 bytes de entrada esperando un grupo completo de 3 bytes. Si no cierras el OutputStream envolvente, los últimos 1-4 caracteres Base64 (incluido el relleno) nunca se escriben.

Solución: Usa try-with-resources o llama a close() explícitamente en el stream envolvente antes de leer la salida.

Before · Java
After · Java
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream b64os = Base64.getEncoder().wrap(baos);
b64os.write(data);
// baos.toString() está INCOMPLETO — faltan los bytes finales
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (OutputStream b64os = Base64.getEncoder().wrap(baos)) {
    b64os.write(data);
}  // close() vacía el relleno final
String encoded = baos.toString();  // completo

Métodos de codificación Base64 — Comparativa

Método
URL-Safe
Streaming
Saltos de línea
Tipos personalizados
Requiere instalación
Base64.getEncoder()
✓ (wrap)
No (JDK 8+)
Base64.getUrlEncoder()
✓ (wrap)
No (JDK 8+)
Base64.getMimeEncoder()
✓ (wrap)
✓ (76 chars)
No (JDK 8+)
Apache Commons Codec
Dependencia Maven
Guava BaseEncoding
✓ (configurable)
Dependencia Maven
jcmd / CLI base64
✓ (pipe)
N/A
Instalación del sistema

Para la mayoría de proyectos: java.util.Base64 es la elección correcta. Sin dependencias, incluido en el JDK, thread-safe y cubre las tres variantes del RFC 4648. Recurre a Apache Commons Codec solo si ya está en tu classpath y necesitas el método de validación isBase64() o el Base64OutputStream para streaming. El BaseEncoding de Guava es una opción razonable si tu proyecto ya depende de Guava, pero añadir una dependencia de 3 MB solo para Base64 es difícil de justificar.

Tres escenarios, tres opciones: ¿un servicio web estándar que necesita codificación para Basic Auth o JWT? Usa el JDK. ¿Un proyecto heredado que ya incluye Commons Codec a través de Spring o Apache HTTP Client? Úsalo — no tiene sentido tener dos librerías Base64 en el classpath. ¿Un proyecto que usa Guava para caché y colecciones? Usa BaseEncoding por su limpia API fluida. Nunca añadas una librería solo para codificación Base64 — la versión del JDK es suficientemente buena desde 2014.

Si necesitas verificar rápidamente un resultado codificado sin ejecutar tu código Java, pégalo en el Codificador Base64 para confirmar que la salida coincide con lo que produce tu código.

Preguntas frecuentes

¿Cómo se codifica un String en Base64 en Java?

Primero convierte el string a bytes con getBytes(StandardCharsets.UTF_8) y luego pasa el arreglo de bytes a Base64.getEncoder().encodeToString(). Especifica siempre UTF-8 de forma explícita: llamar a getBytes() sin un argumento de charset usa el predeterminado de la plataforma, que varía entre sistemas operativos y configuraciones de JVM.

Java
import java.util.Base64;
import java.nio.charset.StandardCharsets;

String payload = "grant_type=client_credentials&scope=read:metrics";
String encoded = Base64.getEncoder()
    .encodeToString(payload.getBytes(StandardCharsets.UTF_8));
// Z3JhbnRfdHlwZT1jbGllbnRfY3JlZGVudGlhbHMmc2NvcGU9cmVhZDptZXRyaWNz

¿Cuál es la diferencia entre Base64.getEncoder() y Base64.getUrlEncoder()?

Ambos codifican en Base64, pero getUrlEncoder() usa el alfabeto URL-safe definido en la sección 5 del RFC 4648. Reemplaza + por - y / por _ para que la salida pueda aparecer en URLs y nombres de archivo sin necesidad de percent-encoding. El codificador estándar usa + y / que entran en conflicto con los parámetros de consulta y los segmentos de ruta de las URLs.

Java
byte[] data = "subject=usr_7b3c&role=admin".getBytes(StandardCharsets.UTF_8);

String standard = Base64.getEncoder().encodeToString(data);
// c3ViamVjdD11c3JfN2IzYyZyb2xlPWFkbWlu

String urlSafe = Base64.getUrlEncoder().encodeToString(data);
// c3ViamVjdD11c3JfN2IzYyZyb2xlPWFkbWlu
// (igual aquí, pero con + → - y / → _ cuando aparecen esos caracteres)

¿Es java.util.Base64 igual en Java 8 y Java 17?

Sí. La API de java.util.Base64 no ha cambiado desde que se introdujo en Java 8. La clase, sus clases anidadas Encoder y Decoder, y todos los métodos de fábrica (getEncoder, getUrlEncoder, getMimeEncoder) son idénticos en Java 8, 11, 17 y 21. No se necesitan migraciones ni cambios de código al actualizar la versión del JDK.

Java
// Este código compila y se ejecuta de forma idéntica en Java 8 hasta Java 21+
import java.util.Base64;
import java.nio.charset.StandardCharsets;

String encoded = Base64.getEncoder()
    .encodeToString("stable-api".getBytes(StandardCharsets.UTF_8));
System.out.println(encoded);  // c3RhYmxlLWFwaQ==

¿Cómo se codifica un archivo en Base64 en Java?

Lee el archivo en un arreglo de bytes con Files.readAllBytes(Path) y pásalo a Base64.getEncoder().encodeToString(). Para archivos grandes que no deben cargarse completamente en memoria, usa Base64.getEncoder().wrap(OutputStream) para transmitir la salida codificada.

Java
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;

byte[] fileBytes = Files.readAllBytes(Path.of("config/tls-cert.pem"));
String encoded = Base64.getEncoder().encodeToString(fileBytes);

¿Por qué se deprecó sun.misc.BASE64Encoder?

sun.misc.BASE64Encoder era una clase interna del JDK que nunca formó parte de la API pública. Vivía en el paquete sun.misc, que Oracle desaconsejó explícitamente usar. Java 8 introdujo java.util.Base64 como el reemplazo oficial, público y soportado. Desde Java 9 y el sistema de módulos, acceder a las clases de sun.misc genera advertencias o errores según la configuración del JDK.

Java
// Forma antigua — NO usar, eliminada en JDKs modernos
// import sun.misc.BASE64Encoder;
// String encoded = new BASE64Encoder().encode(data);

// Forma correcta desde Java 8
import java.util.Base64;
String encoded = Base64.getEncoder().encodeToString(data);

¿Cómo se hace un ciclo completo de codificación y decodificación Base64 en Java?

Codifica con Base64.getEncoder().encodeToString(bytes) y decodifica con Base64.getDecoder().decode(encodedString). Convierte el arreglo de bytes decodificado de vuelta a un String usando new String(bytes, StandardCharsets.UTF_8). El ciclo completo preserva los datos originales exactamente, siempre que uses el mismo charset tanto en getBytes() como en new String().

Java
import java.util.Base64;
import java.nio.charset.StandardCharsets;

// Codificar
String original = "session_token=eyJhbGciOiJSUzI1NiJ9";
byte[] originalBytes = original.getBytes(StandardCharsets.UTF_8);
String encoded = Base64.getEncoder().encodeToString(originalBytes);

// Decodificar
byte[] decodedBytes = Base64.getDecoder().decode(encoded);
String decoded = new String(decodedBytes, StandardCharsets.UTF_8);

System.out.println(original.equals(decoded));  // true

Herramientas relacionadas

  • Decodificador Base64Decodifica strings Base64 de vuelta a su texto u forma binaria original — la operación inversa a la codificación.
  • Codificador de URLAplica percent-encoding a strings para usarlos de forma segura en URLs — distinto del encoding URL-safe de Base64, pero frecuentemente usado junto a él.
  • Decodificador JWTInspecciona tokens JWT cuyos segmentos de encabezado y payload están codificados en Base64url como JSON — decodifícalos sin necesidad de una librería.
  • Formateador JSONFormatea payloads JSON antes o después de la codificación Base64 — útil para depurar integraciones con APIs.
También disponible en:JavaScriptPython
AO
Aisha OseiJava Security & API Engineer

Aisha is a Java engineer specialising in application security, Spring Security, and API design. She has worked on identity and access management systems, OAuth 2.0 integrations, and microservice security at scale. She writes about secure Java coding practices, token validation, cryptographic utilities, and the Spring ecosystem from a security-first perspective.

PN
Pavel NovakRevisor técnico

Pavel is a backend engineer with deep roots in the JVM ecosystem, working primarily with Java and Kotlin. He has extensive experience building data-intensive services and integrating third-party APIs at scale. He writes about modern Java features, the Jackson ecosystem, serialisation patterns, and practical approaches to keeping large codebases maintainable.