Comparison
Base64 vs base64url: dois caracteres que fazem diferença
Mesmo alfabeto, dois últimos caracteres diferentes, padding diferente. Uma linha de diferença, casos de uso totalmente distintos.
By Buğra SözeriPublished
Resumo. Base64 e base64url são a mesma codificação, exceto por três detalhes definidos no RFC 4648: + vira -, / vira _, e o padding = é removido. Use base64url sempre que o valor codificado viajar em uma URL, JWT ou cookie assinado; use Base64 padrão para anexos de e-mail, HTTP Basic Auth e URIs de dados.
Ambos são definidos no RFC 4648. O Base64 padrão (§4) e o base64url (§5) diferem em exatamente três detalhes: duas substituições de alfabeto e o tratamento do padding. Só isso. Mas misturá-los quebra JWTs, cookies assinados e tudo que viaja em uma URL.
A diferença
| Propriedade | Base64 padrão | Base64url |
|---|---|---|
| 62º caractere | + | - |
| 63º caractere | / | _ |
| Padding | = para múltiplo de 4 | Normalmente omitido |
| Seguro para URL? | Não (+, /, = precisam de codificação percentual) | Sim |
| Definido em | RFC 4648 §4 | RFC 4648 §5 |
A mesma entrada, ambas as codificações
Codificando https://example.com/?q=hello world:
- Padrão:
aHR0cHM6Ly9leGFtcGxlLmNvbS8/cT1oZWxsbyB3b3JsZA== - Base64url:
aHR0cHM6Ly9leGFtcGxlLmNvbS8_cT1oZWxsbyB3b3JsZA
Note que o / na forma padrão vira_ em base64url, e o == final é removido.
Por que URLs precisam de sua própria variante
O alfabeto Base64 padrão inclui + e/. Ambos são reservados na sintaxe de URL:
/é o separador de caminho.+é, por convenção em query strings codificadas por formulário, interpretado como espaço.=é o delimitador chave-valor em query strings.
Incorporar uma string Base64 padrão em uma URL requer codificação percentual dos três: + vira%2B, / vira %2F,= vira %3D. A string fica maior e mais difícil de ler. O base64url evita a codificação percentual escolhendo caracteres que já são seguros para URL.
Por que o padding é opcional no base64url
O Base64 padrão sempre completa a saída para um múltiplo de 4 caracteres usando =. Isso não é matematicamente necessário — o decodificador pode inferir o comprimento original a partir do comprimento da saída módulo 4. O padding existe para decodificadores de streaming que precisam saber o limite entre blocos concatenados.
O base64url omite o padding porque: (a) é redundante, (b) = precisa de codificação percentual em URLs, e (c) sinais de igual no final de URLs às vezes confundem analisadores de caminho, CDNs e chaves de cache.
Onde cada um é usado
| Caso de uso | Variante |
|---|---|
| Anexos de e-mail (MIME) | Base64 padrão |
HTTP Basic Auth (Authorization: Basic …) | Base64 padrão |
URIs de dados (data:image/png;base64,…) | Base64 padrão |
| JWT (todos os três segmentos) | Base64url, sem padding |
| OAuth 2.0 PKCE code verifier/challenge | Base64url, sem padding |
| WebPush chaves de mensagem, JOSE/JWS/JWE | Base64url, sem padding |
| Cookies assinados (Rails, Django, etc.) | Base64url, sem padding |
O problema na decodificação
O decodificador Base64 padrão de muitas bibliotecas falha com entradas base64url. O base64.b64decode do Python rejeita - e _; o Buffer.from(s, "base64") do Node.js é permissivo, mas o inverso (.toString("base64")) produz Base64 padrão.
Soluções entre linguagens: substitua antes de decodificar.
// base64url → Base64 padrão
const standard = base64url
.replace(/-/g, "+")
.replace(/_/g, "/")
.padEnd(Math.ceil(base64url.length / 4) * 4, "=");Melhor: use uma biblioteca que suporte explicitamente base64url (Node 16+ tem Buffer.from(s, "base64url"); Python tem base64.urlsafe_b64decode).
A regra prática
Se o valor codificado aparecer em uma URL, em um JWT, em um cookie assinado ou como segmento de caminho — use base64url. Se for para um anexo de e-mail, cabeçalho HTTP (exceto cookies) ou URI de dados JSON — use Base64 padrão.
Nosso codificador Base64 suporta ambas as variantes, com alternância de alfabeto. O decodificador JWT assume base64url porque o padrão exige isso.
Fatos numéricos
- Comprimento codificado: ambas as variantes expandem binário exatamente 4/3 (
ceil(n/3)*4). 100 bytes de entrada → 136 chars de saída em Base64 padrão, ou 134 chars sem padding em base64url. - Overhead de padding: o Base64 padrão adiciona 0, 1 ou 2 chars
=por string codificada — no máximo 1,5% de penalidade de tamanho para payloads curtos, negligível para longos. - Custo de codificação percentual em URLs: cada
+ / =no Base64 padrão se expande para 3 bytes (%2B %2F %3D) quando codificado em URL. Para um JWT de 512 chars, isso são tipicamente 30 a 60 bytes desperdiçados — o base64url evita completamente. - Tamanho do alfabeto: 64 caracteres em ambos, então cada caractere de saída carrega exatamente 6 bits de entrada.
- Tamanhos dos segmentos JWT (RFC 7519): cabeçalho típico 40-50 chars, payload 100-400 chars, assinatura HS256 43 chars (exatamente 32 bytes / 6 = 43 chars base64url, sem padding).
- Throughput: o
Buffer.from(s, "base64")do Node 20 decodifica a ~2 GB/s; obase64.b64decodedo Python a ~600 MB/s em laptop de 2024.
Matriz de decisão
| Onde o valor vive | Escolha |
|---|---|
| Caminho ou query string de URL | base64url, sem padding |
| JWT (cabeçalho / payload / assinatura) | base64url, sem padding (RFC 7519) |
| OAuth 2.0 PKCE verifier | base64url, sem padding (RFC 7636 §4.1) |
| Cookie assinado (Rails / Django / Express) | base64url, sem padding |
URI data: em HTML/CSS | Base64 padrão com padding |
| Anexo de e-mail MIME | Base64 padrão com padding, quebra de linha 76 chars (RFC 2045) |
| Cabeçalho HTTP Basic Auth | Base64 padrão (RFC 7617) |
| Chaves de assinatura WebPush | base64url, sem padding (RFC 8291) |
Fontes
- RFC 4648 — The Base16, Base32, and Base64 Data Encodings — rfc-editor.org/rfc/rfc4648 (§4 padrão, §5 seguro para URL).
- RFC 7519 — JSON Web Token (JWT), exige base64url sem padding — rfc-editor.org/rfc/rfc7519.
- RFC 7636 — OAuth 2.0 PKCE, §4.1 especifica desafio SHA-256 codificado em base64url — rfc-editor.org/rfc/rfc7636.
Frequently asked questions
- Posso decodificar base64url com um decodificador Base64 padrão?
- Às vezes — o Buffer.from do Node é permissivo, o b64decode do Python não é. A abordagem segura entre linguagens: substitua '-' por '+', '_' por '/', e adicione padding até um múltiplo de 4 com '=' antes de decodificar. Runtimes modernos fornecem decodificadores base64url explícitos (Node 16+, urlsafe_b64decode do Python) que tratam isso diretamente.
- Por que o base64url remove o padding?
- Três razões: é matematicamente redundante (os decodificadores podem inferir o comprimento original a partir do comprimento da saída mod 4), o caractere '=' precisa de codificação percentual em URLs, e '=' no final confunde alguns analisadores de caminho, CDNs e chaves de cache.
- Os segmentos JWT são sempre base64url?
- Sim. O RFC 7519 exige base64url sem padding para todos os três segmentos JWT (cabeçalho, payload, assinatura). Codificar um JWT com Base64 padrão produz um token que não será verificado em nenhuma biblioteca compatível.
- O base64url economiza bytes em comparação com o Base64 padrão?
- Marginalmente — o mesmo tamanho de alfabeto significa o mesmo comprimento codificado antes do padding. Remover o padding economiza 0 a 2 bytes por codificação. A economia real é evitar a codificação percentual (cada %XX são 3 bytes para 1), o que pode economizar 6 a 9 bytes por string Base64 em uma URL.
Related
Published May 16, 2026