Base64 Decode Java — Guía de getDecoder().decode()

·Backend Engineer·Revisado porAisha Osei·Publicado

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

Probar Decodificador Base64 Online online →

La decodificación Base64 en Java es algo a lo que recurro cada pocos días — extraer secretos de variables de entorno de Kubernetes, leer payloads binarios de APIs REST, inspeccionar tokens JWT durante una sesión de depuración. La clase integrada java.util.Base64 de Java (desde JDK 8) ofrece tres variantes de decodificador: getDecoder() para Base64 estándar, getUrlDecoder() para entrada URL-safe, y getMimeDecoder() para datos con saltos de línea como adjuntos de correo electrónico. Para una verificación rápida sin escribir código, el decodificador Base64 de ToolDeck lo resuelve al instante en tu navegador. Esta guía está orientada a Java 8+ y cubre los tres decodificadores, streaming con wrap(InputStream), extracción de payloads JWT, decodificación de archivos y respuestas de API, Apache Commons Codec como alternativa, y los cuatro errores que producen salida corrupta en producción.

  • Base64.getDecoder().decode(s) es el enfoque estándar — integrado en java.util.Base64 desde JDK 8, sin dependencias adicionales.
  • Usa getUrlDecoder() para tokens JWT y payloads OAuth — utilizan el alfabeto - y _, no + y /.
  • getMimeDecoder() ignora saltos de línea y espacios en blanco, siendo la opción correcta para adjuntos de correo y certificados PEM.
  • decoder.wrap(InputStream) decodifica al vuelo para archivos grandes sin cargar todo en memoria.
  • El decodificador básico es estricto — saltos de línea al final, espacios o caracteres del alfabeto incorrecto lanzan IllegalArgumentException de inmediato.

¿Qué es la decodificación Base64?

La codificación Base64 convierte datos binarios en una representación ASCII de 64 caracteres para que puedan viajar de forma segura por canales que solo admiten texto — campos JSON, cabeceras HTTP, documentos XML, cuerpos de correo electrónico. La decodificación invierte este proceso: cada 4 caracteres Base64 se mapean de vuelta a 3 bytes originales. El padding = al final indica cuántos bytes se añadieron para completar el último grupo. Base64 no es cifrado — cualquiera puede revertirlo. Su propósito es la seguridad en el transporte, no el secreto.

Escenarios típicos de decodificación en Java: extraer valores de configuración inyectados como variables de entorno Base64, desempaquetar contenido de archivos binarios de respuestas de APIs en la nube, leer certificados codificados en PEM e inspeccionar payloads de tokens JWT durante la depuración.

Before · text
After · text
ZGItcHJvZC51cy1lYXN0LTEuYW1hem9uYXdzLmNvbTo1NDMy
db-prod.us-east-1.amazonaws.com:5432

Base64.getDecoder().decode() — El método de decodificación estándar

La clase java.util.Base64 se añadió en JDK 8 y reemplazó al antiguo sun.misc.BASE64Decoder del que todos dependían. No se necesitan dependencias externas — basta con import java.util.Base64 y llamar a Base64.getDecoder().decode(). El método acepta un String o un byte[] y retorna un byte[] con los datos decodificados.

Ejemplo mínimo funcional

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

public class DecodeCredential {
    public static void main(String[] args) {
        // Kubernetes secret value, Base64-encoded
        String encoded = "ZGItcHJvZC51cy1lYXN0LTEuYW1hem9uYXdzLmNvbTo1NDMy";

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

        System.out.println(connectionString);
        // db-prod.us-east-1.amazonaws.com:5432
    }
}

Especifica siempre StandardCharsets.UTF_8 al construir el String. El constructor new String(bytes) sin argumentos utiliza la codificación predeterminada de la plataforma, que varía entre sistemas. En un servidor Windows con Cp1252 como predeterminado, los caracteres UTF-8 multibyte se corrompen silenciosamente.

Verificación de ida y vuelta

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

public class RoundTrip {
    public static void main(String[] args) {
        String original = "redis://cache-prod.internal:6379/session-store";

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

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

        System.out.println(recovered.equals(original)); // true
    }
}

Decodificación en un buffer preasignado

La sobrecarga de tres argumentos decode(byte[] src, byte[] dst) escribe directamente en un buffer de destino y retorna el número de bytes escritos. Esto evita una asignación extra en rutas de código críticas:

Java 8+
import java.util.Base64;

public class DecodeToBuffer {
    public static void main(String[] args) {
        byte[] src = "eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0M30=".getBytes();
        byte[] dst = new byte[1024]; // pre-allocated

        int len = Base64.getDecoder().decode(src, dst);
        String result = new String(dst, 0, len);

        System.out.println(result);
        // {"host":"10.0.1.50","port":8443}
    }
}
Nota:decode() lanza IllegalArgumentException si la entrada contiene caracteres fuera del alfabeto Base64 (incluyendo saltos de línea y espacios). Si tu entrada puede tener espacios en blanco, cambia a getMimeDecoder() o elimínalos con encoded.strip() antes de decodificar.

Decodificación Base64 con tipos no estándar y objetos personalizados

El byte[] en bruto de decode() a menudo necesita convertirse en algo más específico: un UUID, un objeto Java serializado, un mensaje protobuf o un timestamp. El decodificador siempre retorna bytes — la conversión a tipos de dominio es responsabilidad tuya.

Base64 a UUID

Java 8+
import java.util.Base64;
import java.nio.ByteBuffer;
import java.util.UUID;

public class DecodeUUID {
    public static UUID fromBase64(String encoded) {
        byte[] bytes = Base64.getUrlDecoder().decode(encoded);
        ByteBuffer bb = ByteBuffer.wrap(bytes);
        return new UUID(bb.getLong(), bb.getLong());
    }

    public static void main(String[] args) {
        // Compact Base64-encoded UUID from an API response
        String encoded = "f47ac10b-58cc-4372-a567-0e02b2c3d479";
        UUID original = UUID.fromString(encoded);

        // Encode to Base64 (compact form — 22 chars vs 36)
        ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
        bb.putLong(original.getMostSignificantBits());
        bb.putLong(original.getLeastSignificantBits());
        String compact = Base64.getUrlEncoder().withoutPadding()
            .encodeToString(bb.array());
        System.out.println(compact); // 9HrBC1jMQ3KlZw4CssPUeQ

        // Decode back
        UUID recovered = fromBase64(compact);
        System.out.println(recovered); // f47ac10b-58cc-4372-a567-0e02b2c3d479
    }
}

Base64 a objeto JSON deserializado con Jackson

Java 8+
import java.util.Base64;
import java.nio.charset.StandardCharsets;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.Instant;

public class DecodeJsonPayload {
    record DeployEvent(String service, String region, Instant deployedAt, int replicas) {}

    public static void main(String[] args) throws Exception {
        // Base64-encoded JSON payload from a message queue
        String encoded = "eyJzZXJ2aWNlIjoicGF5bWVudC1nYXRld2F5Iiwi"
            + "cmVnaW9uIjoiZXUtd2VzdC0xIiwiZGVwbG95ZWRBdCI6"
            + "IjIwMjYtMDMtMTVUMTQ6MzA6MDBaIiwicmVwbGljYXMiOjR9";

        byte[] jsonBytes = Base64.getDecoder().decode(encoded);
        String json = new String(jsonBytes, StandardCharsets.UTF_8);
        System.out.println(json);
        // {"service":"payment-gateway","region":"eu-west-1",
        //  "deployedAt":"2026-03-15T14:30:00Z","replicas":4}

        ObjectMapper mapper = new ObjectMapper();
        mapper.findAndRegisterModules(); // picks up JavaTimeModule
        DeployEvent event = mapper.readValue(jsonBytes, DeployEvent.class);

        System.out.println(event.service());   // payment-gateway
        System.out.println(event.deployedAt()); // 2026-03-15T14:30:00Z
    }
}
Advertencia:Nunca uses ObjectInputStream para deserializar datos Base64 no confiables. Los ataques de deserialización en Java están bien documentados — si el contenido codificado proviene de una fuente externa, analízalo como JSON o protobuf en lugar de usar la serialización nativa de Java.

Referencia de métodos de Base64.Decoder

Todos los métodos pertenecen a java.util.Base64 y su clase interna Base64.Decoder. Los tres métodos de fábrica en Base64 retornan instancias de decodificador diferentes; los métodos decode() y wrap() pertenecen a la instancia Decoder.

Método
Retorna
Tipo de entrada
Descripción
getDecoder()
Base64.Decoder
Decodificador estándar (RFC 4648 §4, alfabeto + y / con padding =)
getUrlDecoder()
Base64.Decoder
Decodificador URL-safe (RFC 4648 §5, alfabeto - y _ con padding =)
getMimeDecoder()
Base64.Decoder
Decodificador MIME — ignora separadores de línea y caracteres no Base64
decode(String src)
byte[]
String
Decodifica la cadena de entrada a un nuevo array de bytes
decode(byte[] src)
byte[]
byte[]
Decodifica el array de bytes de entrada a un nuevo array de bytes
decode(byte[] src, byte[] dst)
int
byte[] + byte[]
Decodifica en un buffer dst preasignado y retorna los bytes escritos
wrap(InputStream is)
InputStream
InputStream
Retorna un stream que decodifica datos Base64 al vuelo

getMimeDecoder() — Decodificación de Base64 MIME con saltos de línea

El decodificador básico rechaza cualquier elemento fuera del alfabeto Base64 — y eso incluye los saltos de línea \r\n que el contenido codificado en MIME siempre contiene. Los adjuntos de correo electrónico, los certificados PEM y algunas respuestas de API antiguas dividen la salida Base64 en 76 caracteres por línea. getMimeDecoder() ignora silenciosamente los separadores de línea y cualquier carácter que no esté en el alfabeto Base64, por lo que gestiona esto directamente.

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

public class MimeDecode {
    public static void main(String[] args) {
        // PEM certificate body — line-wrapped at 76 characters
        String pemBody = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t\r\n"
            + "TUlJQm96Q0NBVWlnQXdJQkFnSUpBSXBhVDJU\r\n"
            + "aVFvZU1BMEdDU3FHU0liM0RRRU==";

        // getDecoder() lanzaría IllegalArgumentException aquí
        byte[] decoded = Base64.getMimeDecoder().decode(pemBody);
        System.out.println(new String(decoded, StandardCharsets.UTF_8));
        // -----BEGIN CERTIFICATE-----
        // MIIBozCCAUigAwIBAgIJAIpaT2T...
    }
}
Nota:getMimeDecoder() es permisivo: omite los caracteres inválidos en lugar de lanzar una excepción. Esto es adecuado para datos MIME conocidos, pero puede silenciar corrupción en entradas arbitrarias. Usa getDecoder() cuando necesites validación estricta.

Decodificar Base64 desde un archivo y una respuesta de API

Leer un archivo codificado en Base64 desde disco

Los archivos binarios (imágenes, certificados, blobs cifrados) a veces se almacenan en disco como texto Base64. Lee el archivo, decodifica y escribe la salida binaria:

Java 8+
import java.util.Base64;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public class DecodeFile {
    public static void main(String[] args) {
        Path inputPath = Path.of("tls-cert.pem.b64");
        Path outputPath = Path.of("tls-cert.pem");

        try {
            String encoded = Files.readString(inputPath).strip();
            byte[] decoded = Base64.getMimeDecoder().decode(encoded);
            Files.write(outputPath, decoded);

            System.out.printf("Decoded %d bytes → %s%n", decoded.length, outputPath);
        } catch (IOException e) {
            System.err.println("File error: " + e.getMessage());
        } catch (IllegalArgumentException e) {
            System.err.println("Invalid Base64: " + e.getMessage());
        }
    }
}

Decodificar un campo Base64 de una respuesta HTTP de API

Las APIs en la nube (AWS KMS, GitHub Contents, Vault) devuelven frecuentemente datos binarios como cadenas Base64 dentro de JSON. Primero analiza el JSON y luego decodifica el campo objetivo:

Java 11+
import java.util.Base64;
import java.nio.charset.StandardCharsets;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class DecodeApiResponse {
    public static void main(String[] args) {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.example.com/secrets/db-password"))
            .header("Authorization", "Bearer sk-prod-9f8e7d6c")
            .build();

        try {
            HttpResponse<String> response = client.send(
                request, HttpResponse.BodyHandlers.ofString());

            if (response.statusCode() != 200) {
                System.err.printf("Unexpected status: %d%n", response.statusCode());
                return;
            }

            ObjectMapper mapper = new ObjectMapper();
            JsonNode root = mapper.readTree(response.body());

            // API returns: {"name":"db-password","value":"cG9zdGdyZXM6eGs5...","version":3}
            String encodedValue = root.get("value").asText();
            byte[] decoded = Base64.getDecoder().decode(encodedValue);
            String secret = new String(decoded, StandardCharsets.UTF_8);

            System.out.println("Secret: " + secret);
            // Secret: postgres:xk9mP2qR@db-prod:5432/orders
        } catch (Exception e) {
            System.err.println("Failed to fetch secret: " + e.getMessage());
        }
    }
}
Nota:Envuelve la llamada a decode en su propio bloque try-catch para IllegalArgumentException por separado de los errores de red. Mezclar excepciones de I/O con fallos de decodificación dificulta la depuración — quieres saber de inmediato si la API devolvió datos incorrectos o si fue la red la que falló.

Decodificación Base64 desde la línea de comandos

No siempre necesitas un programa Java. Todos los sistemas Linux y macOS tienen el comando base64, y JDK 9+ incluye jshell para instrucciones Java interactivas. Para una inspección rápida durante la depuración, estas opciones son más rápidas que compilar una clase.

bash
# Decode a Base64 string (Linux / macOS)
echo "eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0M30=" | base64 --decode
# {"host":"10.0.1.50","port":8443}

# Decode and pretty-print with jq
echo "eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0M30=" | base64 --decode | jq .
# {
#   "host": "10.0.1.50",
#   "port": 8443
# }

# Quick decode with jshell (JDK 9+)
echo 'System.out.println(new String(java.util.Base64.getDecoder().decode("c2VydmVyLWNvbmZpZw==")))' | jshell -
# server-config

# macOS uses -D instead of --decode
echo "c2VydmVyLWNvbmZpZw==" | base64 -D

Para pegar cadenas codificadas directamente en un navegador, el decodificador Base64 de ToolDeck gestiona tanto las variantes estándar como las URL-safe sin ninguna configuración.

Alternativa de alto rendimiento: Apache Commons Codec

La clase integrada java.util.Base64 de Java ya está bien optimizada — JDK 11+ usa intrínsecos en x86 para codificación y decodificación. Para la mayoría de las aplicaciones, no hay razón para recurrir a una librería de terceros. Dicho esto, Apache Commons Codec sigue siendo popular en bases de código legacy y ofrece Base64InputStream para decodificación en streaming con gestión automática de espacios en blanco.

XML (Maven)
<!-- pom.xml -->
<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.17.0</version>
</dependency>
Java 8+
import org.apache.commons.codec.binary.Base64;

public class CommonsCodecDecode {
    public static void main(String[] args) {
        // Commons Codec is more lenient — handles whitespace and line breaks
        String encoded = "eyJob3N0IjoiMTAuMC4xLjUw\nIiwicG9ydCI6ODQ0M30=";
        byte[] decoded = Base64.decodeBase64(encoded);

        System.out.println(new String(decoded));
        // {"host":"10.0.1.50","port":8443}
    }
}

La principal ventaja de Commons Codec frente a la API integrada es su permisividad con los espacios en blanco por defecto y su clase Base64InputStream, que es anterior al decoder.wrap() de Java. Si usas Java 8+, la API integrada cubre todo lo que hace Commons Codec. Solo recurro a Commons Codec cuando el proyecto ya depende de él.

Streaming de archivos Base64 grandes con decoder.wrap()

Cargar un archivo Base64 de 200 MB con Files.readString() y luego llamar a decode() asigna aproximadamente 350 MB de heap: la cadena codificada más el array de bytes decodificados. decoder.wrap(InputStream) decodifica al vuelo, manteniendo el uso de memoria constante.

Java 8+
import java.util.Base64;
import java.io.*;
import java.nio.file.*;

public class StreamDecode {
    public static void main(String[] args) throws IOException {
        Path src = Path.of("database-dump.sql.b64");
        Path dst = Path.of("database-dump.sql");

        try (InputStream in = Base64.getMimeDecoder().wrap(
                 new BufferedInputStream(Files.newInputStream(src)));
             OutputStream out = new BufferedOutputStream(Files.newOutputStream(dst))) {

            byte[] buffer = new byte[8192];
            int bytesRead;
            long total = 0;
            while ((bytesRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
                total += bytesRead;
            }
            System.out.printf("Decoded %d bytes → %s%n", total, dst);
        }
    }
}

En Java 9+ puedes sustituir el bucle de lectura por in.transferTo(out) — hace lo mismo con menos código. Usa getMimeDecoder().wrap() en lugar de getDecoder().wrap() si el archivo puede contener saltos de línea (archivos PEM, exportaciones de correo).

Java 9+
import java.util.Base64;
import java.io.*;
import java.nio.file.*;

public class StreamDecodeSimple {
    public static void main(String[] args) throws IOException {
        try (InputStream in = Base64.getMimeDecoder().wrap(
                 new BufferedInputStream(Files.newInputStream(Path.of("backup.tar.b64"))));
             OutputStream out = Files.newOutputStream(Path.of("backup.tar"))) {
            in.transferTo(out); // Java 9+
        }
    }
}
Advertencia:getDecoder().wrap() no tolera saltos de línea en el stream. Si los datos Base64 tienen saltos de línea (divididos en 76 chars), usa getMimeDecoder().wrap() en su lugar — de lo contrario el stream produce silenciosamente salida corrupta o lanza una excepción en una posición de lectura impredecible.

Decodificar el payload JWT en Base64 en Java sin librería JWT

Un JWT son tres segmentos codificados en Base64url unidos por puntos. El segmento central es el payload — la parte que te interesa durante la depuración. Puedes decodificarlo sin importar jjwt ni Nimbus. Divide por ., decodifica la segunda parte con getUrlDecoder() y analiza el JSON resultante:

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

public class JWTInspect {
    public static String decodeJwtPayload(String token) {
        String[] parts = token.split("\\.");
        if (parts.length != 3) {
            throw new IllegalArgumentException(
                "Invalid JWT: expected 3 segments, got " + parts.length);
        }
        // JWT uses URL-safe Base64 without padding
        byte[] payload = Base64.getUrlDecoder().decode(parts[1]);
        return new String(payload, StandardCharsets.UTF_8);
    }

    public static void main(String[] args) {
        String token = "eyJhbGciOiJSUzI1NiJ9"
            + ".eyJzdWIiOiJ1c3ItNjcyIiwiaXNzIjoiYXV0aC5leGFtcGxlLmNvbSIs"
            + "ImV4cCI6MTc0MTk1NjgwMCwicm9sZXMiOlsiYWRtaW4iLCJiaWxsaW5nIl19"
            + ".SIGNATURE_PLACEHOLDER";

        String payload = decodeJwtPayload(token);
        System.out.println(payload);
        // {"sub":"usr-672","iss":"auth.example.com",
        //  "exp":1741956800,"roles":["admin","billing"]}
    }
}

Errores comunes

Me he encontrado con cada uno de estos en revisiones de código, y los dos primeros representan la gran mayoría de los bugs en producción relacionados con Base64 en servicios Java.

Usar getDecoder() con entrada URL-safe

Problema: Los tokens JWT y los tokens de acceso OAuth usan el alfabeto URL-safe (- y _). Pasárselos a getDecoder() lanza IllegalArgumentException porque - no está en el alfabeto Base64 estándar.

Solución: Verifica la fuente de tus datos: los tokens de sistemas de autenticación necesitan getUrlDecoder(); los adjuntos MIME necesitan getMimeDecoder().

Before · Java
After · Java
// JWT header — URL-safe, no padding
String header = "eyJhbGciOiJSUzI1NiJ9";
byte[] decoded = Base64.getDecoder().decode(header);
// IllegalArgumentException: Illegal base64 character 2d
String header = "eyJhbGciOiJSUzI1NiJ9";
byte[] decoded = Base64.getUrlDecoder().decode(header);
System.out.println(new String(decoded));
// {"alg":"RS256"}
No especificar el charset al construir el String

Problema: new String(bytes) usa el charset predeterminado de la JVM, que varía entre entornos. Un servidor CI Linux (UTF-8) y un host de producción Windows (Cp1252) producen resultados distintos para los mismos bytes.

Solución: Pasa siempre StandardCharsets.UTF_8 como segundo argumento.

Before · Java
After · Java
byte[] decoded = Base64.getDecoder().decode(encoded);
String result = new String(decoded);
// platform-dependent — may corrupt multi-byte characters
byte[] decoded = Base64.getDecoder().decode(encoded);
String result = new String(decoded, StandardCharsets.UTF_8);
// consistent across all platforms
Decodificar una cadena con espacios en blanco al final

Problema: Las cadenas Base64 pegadas desde terminales o leídas desde archivos de configuración suelen tener saltos de línea al final. El decodificador básico rechaza cualquier carácter fuera del alfabeto Base64.

Solución: Llama a .strip() en la entrada antes de decodificar, o cambia a getMimeDecoder() que ignora los espacios en blanco.

Before · Java
After · Java
// Read from environment variable — has a trailing newline
String encoded = System.getenv("DB_PASSWORD_B64"); // "cG9zdGdyZXM=
"
byte[] decoded = Base64.getDecoder().decode(encoded);
// IllegalArgumentException: Illegal base64 character a
String encoded = System.getenv("DB_PASSWORD_B64");
byte[] decoded = Base64.getDecoder().decode(encoded.strip());
System.out.println(new String(decoded, StandardCharsets.UTF_8));
// postgres
Convertir datos binarios a String

Problema: Llamar a new String(decoded) sobre contenido binario (imágenes, protobuf, blobs cifrados) produce un String inválido. Convertirlo de vuelta a bytes después corrompe silenciosamente los datos porque el constructor String reemplaza las secuencias UTF-8 inválidas.

Solución: Mantén los datos binarios como byte[] a lo largo de todo tu pipeline. Solo convierte a String cuando sepas que el contenido es texto.

Before · Java
After · Java
byte[] decoded = Base64.getDecoder().decode(pngBase64);
String imageStr = new String(decoded); // corrupts binary
Files.writeString(Path.of("image.png"), imageStr); // broken file
byte[] decoded = Base64.getDecoder().decode(pngBase64);
// Write bytes directly — no String conversion
Files.write(Path.of("image.png"), decoded);

Comparación de métodos

Los decodificadores integrados cubren la mayoría de los casos de uso. Apache Commons Codec y Guava son alternativas que puedes encontrar en bases de código antiguas.

Método
Variante de codificación
Ignora espacios en blanco
Streaming
Tipos personalizados
Requiere instalación
Base64.getDecoder()
Estándar (+, /)
No (JDK 8+)
Base64.getUrlDecoder()
URL-safe (-, _)
No (JDK 8+)
Base64.getMimeDecoder()
MIME (saltos de línea OK)
No (JDK 8+)
decoder.wrap(InputStream)
Cualquier variante
Depende del decodificador
No (JDK 8+)
Apache Commons Base64InputStream
Estándar / URL-safe
Sí (commons-codec)
Apache Commons Base64.decodeBase64()
Estándar
Sí (commons-codec)
Guava BaseEncoding.base64().decode()
Estándar
Sí (guava)

Para tokens JWT y payloads de APIs modernas: getUrlDecoder(). Para adjuntos de correo electrónico y certificados PEM: getMimeDecoder(). Para archivos grandes donde la memoria importa: decoder.wrap(InputStream). Para todo lo demás: getDecoder(). Apache Commons Codec solo tiene sentido si ya está en tu árbol de dependencias.

Para una verificación rápida durante el desarrollo, el decodificador Base64 online es más rápido que escribir una clase temporal.

Preguntas frecuentes

¿Cómo decodifico una cadena Base64 en Java?

Importa java.util.Base64 y llama a Base64.getDecoder().decode(encodedString). Retorna un byte[] — envuélvelo con new String(bytes, StandardCharsets.UTF_8) para obtener texto legible. Para Base64 URL-safe (usado en JWTs), sustituye getDecoder() por getUrlDecoder().

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

byte[] decoded = Base64.getDecoder().decode("c2VydmVyLWNvbmZpZw==");
String result = new String(decoded, StandardCharsets.UTF_8);
System.out.println(result); // server-config

¿Cuál es la diferencia entre getDecoder() y getMimeDecoder() en Java?

getDecoder() es estricto — rechaza cualquier carácter fuera del alfabeto Base64, incluidos los saltos de línea. getMimeDecoder() tolera separadores de línea (\r\n) e ignora cualquier carácter que no pertenezca al alfabeto Base64, lo que lo convierte en la opción correcta para decodificar adjuntos de correo electrónico y certificados PEM donde los datos se dividen en líneas de 76 caracteres.

Java 8+
String wrapped = "c2VydmVyLWNv\r\nbmZpZw==";

// getDecoder() lanza IllegalArgumentException
// Base64.getDecoder().decode(wrapped); // FALLA

// getMimeDecoder() lo maneja correctamente
byte[] decoded = Base64.getMimeDecoder().decode(wrapped);
System.out.println(new String(decoded)); // server-config

¿Cómo decodifico una cadena Base64 URL-safe en Java?

Usa Base64.getUrlDecoder().decode(encoded). El decodificador URL espera el alfabeto - y _ definido en RFC 4648 §5 en lugar de + y /. Los tokens JWT siempre usan este alfabeto. Si los caracteres de padding (=) fueron eliminados (común en JWTs), el decodificador URL lo gestiona igualmente — el decodificador URL de Java acepta tanto entrada con padding como sin él.

Java 8+
import java.util.Base64;

// Cabecera JWT — URL-safe, sin padding
String jwtHeader = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
byte[] decoded = Base64.getUrlDecoder().decode(jwtHeader);
System.out.println(new String(decoded));
// {"alg":"HS256","typ":"JWT"}

¿Cómo decodifico en streaming un archivo Base64 grande en Java?

Usa decoder.wrap(inputStream) para envolver un FileInputStream. El InputStream retornado decodifica Base64 al vuelo mientras lees bytes, por lo que el uso de memoria se mantiene constante independientemente del tamaño del archivo. Pásalo por un BufferedInputStream o directamente a Files.copy() para mejor rendimiento.

Java 8+
import java.util.Base64;
import java.io.*;
import java.nio.file.*;

try (InputStream in = Base64.getDecoder().wrap(
        new BufferedInputStream(new FileInputStream("payload.b64")));
     OutputStream out = new FileOutputStream("payload.bin")) {
    in.transferTo(out);
}

¿Por qué Base64.getDecoder().decode() lanza IllegalArgumentException?

El decodificador básico es estricto: rechaza saltos de línea, espacios y cualquier carácter fuera del rango A-Za-z0-9+/=. Tres causas habituales: la entrada tiene saltos de línea al final (usa trim), la entrada utiliza caracteres URL-safe como - y _ (cambia a getUrlDecoder()), o la entrada estaba dividida en líneas de 76 caracteres (cambia a getMimeDecoder()). Inspecciona siempre los bytes en bruto si el mensaje de error no es claro.

Java 8+
String raw = "c2VydmVyLWNvbmZpZw==\n"; // salto de línea al final

// Opción 1: eliminar espacios en blanco
byte[] decoded = Base64.getDecoder().decode(raw.strip());

// Opción 2: usar el decodificador MIME que ignora espacios en blanco
byte[] decoded2 = Base64.getMimeDecoder().decode(raw);

¿Puedo decodificar Base64 en Java sin java.util.Base64?

Sí, pero no hay ninguna razón válida para hacerlo en Java 8+. Antes de Java 8, los desarrolladores usaban sun.misc.BASE64Decoder (interno, eliminado en Java 9+), javax.xml.bind.DatatypeConverter.parseBase64Binary() (eliminado en Java 11), o Apache Commons Codec. Los tres están obsoletos o requieren una dependencia adicional. Usa java.util.Base64 — es más rápido, viene incluido en el JDK y cubre las tres variantes (básico, URL-safe, MIME).

Herramientas relacionadas

  • Codificador Base64 — codifica texto o datos binarios a Base64 en el navegador, útil para generar fixtures de prueba para pegar en tus tests unitarios de Java.
  • Decodificador JWT — divide y decodifica los tres segmentos del JWT a la vez, con inspección campo a campo del payload — más rápido que escribir una clase Java cuando solo necesitas leer un token.
  • Decodificador URL — decodifica cadenas con percent-encoding, útil cuando las respuestas de API combinan datos Base64url con parámetros de consulta codificados en porcentaje.
  • Formateador JSON — tras decodificar un payload JWT en Base64 o una configuración de API, pega el JSON aquí para visualizarlo con formato y validar la estructura.
También disponible en:JavaScriptPythonGoC#
PN
Pavel NovakBackend Engineer

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.

AO
Aisha OseiRevisor técnico

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.