Base64-avkodning i Go dyker upp hela tiden — JWT-inspektion, binärfilsbilagor, API-payloads från molntjänster. Go's standardpaket encoding/base64hanterar allt det, men att välja fel kodningsvariant (standard kontra URL-säker, med eller utan utfyllnad) är den i särklass vanligaste orsaken till “illegal base64 data”-fel. Den här guiden täcker StdEncoding, URLEncoding, RawURLEncoding, strömavkodning med base64.NewDecoder, JWT-payloadinspektion och fyra misstag som nästan alla gör första gången. Alla exempel är testade med Go 1.21. För engångsavkodning i webbläsaren gör ToolDeck's Base64 Decoder jobbet direkt utan en enda kodrad.
- ✓encoding/base64 ingår i Go:s standardbibliotek — inget go get behövs
- ✓Använd RawURLEncoding för JWT-tokens och de flesta moderna API:er (ingen utfyllnad, URL-säkert alfabet)
- ✓StdEncoding använder + och / med =-utfyllnad; URLEncoding byter till - och _ men behåller utfyllnaden
- ✓base64.NewDecoder omsluter valfri io.Reader för strömavkodning utan att ladda in allt i minnet
- ✓Kontrollera alltid det returnerade felet — ogiltig utfyllnad och fel alfabet ger illegal base64 data
Vad är Base64-avkodning?
Base64-kodning representerar binärdata som ASCII-text med hjälp av 64 utskrivbara tecken (A–Z, a–z, 0–9 plus två extra). Avkodning reverserar detta — det konverterar ASCII-representationen tillbaka till de ursprungliga bytesen. Var fjärde Base64-tecken avkodas till exakt 3 bytes. Schemat finns till för att många transportlager (e-post, HTTP-headers, JSON-fält) är utformade för text, inte rå binärdata. Nedan visas hur en tur-och-retur ser ut:
package main
import (
"encoding/base64"
"fmt"
)
func main() {
// Raw bytes → Base64 encoded → decoded back to raw bytes
original := []byte("service_token:xK9mP2qR")
// Encoded: "c2VydmljZV90b2tlbjp4SzltUDJxUg=="
encoded := base64.StdEncoding.EncodeToString(original)
decoded, _ := base64.StdEncoding.DecodeString(encoded)
fmt.Println(string(decoded) == string(original)) // true
}Avkoda Base64 i Go med encoding/base64
Paketet encoding/base64 medföljer Go — inga externa beroenden. Det exponerar fyra fördefinierade kodningsvarianter som variabler på paketnivå. Den mest använda funktionen för strängindata är DecodeString, som returnerar en byte-slice och ett fel.
package main
import (
"encoding/base64"
"fmt"
"log"
)
func main() {
// Standard Base64 — the alphabet uses + and / with = padding
encoded := "eyJob3N0IjoiZGItcHJvZCF1cy1lYXN0LTEiLCJwb3J0Ijo1NDMyfQ=="
decoded, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
log.Fatalf("decode error: %v", err)
}
fmt.Println(string(decoded))
// {"host":"db-prod.us-east-1","port":5432}
}Metoden Decode arbetar med byte-slices snarare än strängar och skriver resultatet till en förallokerad destinationsbuffer. Du behöver storleksanpassa bufferten korrekt — använd base64.StdEncoding.DecodedLen(len(src)) för att få den maximala storleken (den kan vara några bytes större än den faktiska avkodade längden på grund av utfyllnad).
package main
import (
"encoding/base64"
"fmt"
"log"
)
func main() {
src := []byte("eyJob3N0IjoiZGItcHJvZCIsInBvcnQiOjU0MzJ9")
dst := make([]byte, base64.RawStdEncoding.DecodedLen(len(src)))
n, err := base64.RawStdEncoding.Decode(dst, src)
if err != nil {
log.Fatalf("decode: %v", err)
}
fmt.Println(string(dst[:n]))
// {"host":"db-prod","port":5432}
}DecodedLen returnerar ett övre gränsvärde, inte den exakta längden. Använd alltid returvärdet n från Decode för att skära ut resultatet korrekt: dst[:n].StdEncoding vs URLEncoding — Att välja rätt variant
Det är här de flesta förvirringar uppstår. Go's encoding/base64 exponerar fyra kodningsobjekt, och att välja fel garanterar ett fel. Skillnaden handlar om två saker: alfabetet och utfyllnaden.
package main
import (
"encoding/base64"
"fmt"
)
func main() {
// JWT header payload — URL-safe, no padding
jwtHeader := "eyJhbGciOiJSUzI1NiIsImtpZCI6IjIwMjMtMDkifQ"
// Wrong: StdEncoding fails on URL-safe input without padding
_, err1 := base64.StdEncoding.DecodeString(jwtHeader)
fmt.Println("StdEncoding error:", err1)
// StdEncoding error: illegal base64 data at input byte 43
// Correct: RawURLEncoding — no padding, URL-safe alphabet
decoded, err2 := base64.RawURLEncoding.DecodeString(jwtHeader)
fmt.Println("RawURLEncoding ok:", err2, "→", string(decoded))
// RawURLEncoding ok: <nil> → {"alg":"RS256","kid":"2023-09"}
}De fyra varianterna i klartext:
Min tumregel: om det kommer från en JWT, ett OAuth-flöde eller ett SDK från en molnleverantör, börja med RawURLEncoding. Kommer det från e-postbilagor eller gammaldags webbformulär, prova StdEncoding. Felmeddelandet anger alltid den exakta byte-positionen där avkodningen misslyckades.
Avkoda Base64 från en fil och ett API-svar
Läsa en Base64-kodad fil
Binärfiler (bilder, PDF:er, certifikat) lagras ibland Base64-kodade på disk. Läs filen, ta bort eventuellt avslutande blanksteg och avkoda sedan:
package main
import (
"encoding/base64"
"fmt"
"log"
"os"
"strings"
)
func main() {
raw, err := os.ReadFile("certificate.pem.b64")
if err != nil {
log.Fatalf("read file: %v", err)
}
// Strip newlines — Base64 files often have line breaks every 76 chars
cleaned := strings.ReplaceAll(strings.TrimSpace(string(raw)), "\n", "")
decoded, err := base64.StdEncoding.DecodeString(cleaned)
if err != nil {
log.Fatalf("decode: %v", err)
}
if err := os.WriteFile("certificate.pem", decoded, 0600); err != nil {
log.Fatalf("write: %v", err)
}
fmt.Printf("decoded %d bytes → certificate.pem\n", len(decoded))
}Avkoda ett Base64-fält från ett API:s JSON-svar
Moln-API:er returnerar ofta binärdata (krypteringsnycklar, signerade blobs, miniatyrbilder) som Base64-strängar inuti JSON. Avmarshala JSON:en först, avkoda sedan målfältet:
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"log"
"net/http"
)
type SecretResponse struct {
Name string `json:"name"`
Payload string `json:"payload"` // Base64-encoded secret value
Version int `json:"version"`
}
func fetchAndDecodeSecret(secretURL string) ([]byte, error) {
resp, err := http.Get(secretURL)
if err != nil {
return nil, fmt.Errorf("http get: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status: %d", resp.StatusCode)
}
var secret SecretResponse
if err := json.NewDecoder(resp.Body).Decode(&secret); err != nil {
return nil, fmt.Errorf("decode json: %w", err)
}
value, err := base64.StdEncoding.DecodeString(secret.Payload)
if err != nil {
return nil, fmt.Errorf("decode base64: %w", err)
}
return value, nil
}
func main() {
value, err := fetchAndDecodeSecret("https://api.example.com/secrets/db-password")
if err != nil {
log.Fatalf("fetch secret: %v", err)
}
fmt.Printf("secret value: %s\n", value)
}fmt.Errorf("decode base64: %w", err) snarare än att tappa kontexten. Det ursprungliga felmeddelandet från encoding/base64 inkluderar byte-positionen för felet, vilket är användbart vid felsökning.Strömavkodning av stora Base64-kodade filer
Att ladda in en 500 MB Base64-kodad fil i minnet med os.ReadFile och sedan anropa DecodeString använder ungefär 750 MB RAM (den kodade strängen plus de avkodade bytesen). base64.NewDecoder omsluter valfri io.Reader och avkodar i bitar, vilket håller minnesanvändningen nära konstant. Kombinera det med io.Copy för en ren strömningspipeline:
package main
import (
"encoding/base64"
"fmt"
"io"
"log"
"os"
)
func streamDecodeFile(srcPath, dstPath string) error {
src, err := os.Open(srcPath)
if err != nil {
return fmt.Errorf("open source: %w", err)
}
defer src.Close()
dst, err := os.Create(dstPath)
if err != nil {
return fmt.Errorf("create dest: %w", err)
}
defer dst.Close()
decoder := base64.NewDecoder(base64.StdEncoding, src)
written, err := io.Copy(dst, decoder)
if err != nil {
return fmt.Errorf("stream decode: %w", err)
}
fmt.Printf("written %d bytes to %s\n", written, dstPath)
return nil
}
func main() {
if err := streamDecodeFile("backup.tar.b64", "backup.tar"); err != nil {
log.Fatal(err)
}
}base64.NewDecoder förväntar sig ren, oavbruten Base64-data. Om källfilen innehåller radbrytningar (vanligt i PEM- och MIME-kodade filer) måste du antingen omsluta källläsaren med en radstrippande läsare eller förbearbeta filen för att ta bort radbrytningar innan strömning.Base64-avkodning från kommandoraden
De flesta Go-utvecklare vänder sig till kommandoraden först vid felsökning. Alla macOS- och Linux-system levereras med base64; på Windows har PowerShell ett inbyggt motsvarighet. För snabb inspektion av API-payloads är dessa snabbare än att skriva ett Go-skript.
# Avkoda en Base64-sträng (Linux / macOS)
echo "eyJob3N0IjoiZGItcHJvZCIsInBvcnQiOjU0MzJ9" | base64 --decode
# {"host":"db-prod","port":5432}
# Avkoda och formatera snyggt med jq (skicka JSON-utdatan)
echo "eyJob3N0IjoiZGItcHJvZCIsInBvcnQiOjU0MzJ9" | base64 --decode | jq .
# {
# "host": "db-prod",
# "port": 5432
# }
# Avkoda en Base64-kodad fil till binär
base64 --decode < encrypted_payload.b64 > encrypted_payload.bin
# macOS använder -D-flaggan istället för --decode
echo "c2VjcmV0LXRva2Vu" | base64 -DFör att inspektera JWT-tokens utan installerade verktyg, klistra in token i ToolDeck's Base64 Decoder — dela på punkterna och avkoda varje del.
Högpresterande alternativ: encoding/base64 är redan snabb
Till skillnad från Python, där orjson kontra jsonär en meningsfull prestandadiskussion, är Go's encoding/base64 redan assemblyoptimerad och genuint snabb för de flesta arbetsbelastningar. Med det sagt — om du bearbetar miljontals poster i en tät loop ger filippo.io/base64 SIMD-accelererad avkodning med en utbytbar API.
go get filippo.io/base64
package main
import (
"fmt"
"log"
"filippo.io/base64"
)
func main() {
// Drop-in replacement — same API as encoding/base64
encoded := "eyJob3N0IjoiY2FjaGUtcHJvZCIsInBvcnQiOjYzNzl9"
decoded, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
log.Fatalf("decode: %v", err)
}
fmt.Println(string(decoded))
// {"host":"cache-prod","port":6379}
}Prestandavinsten syns tydligast på amd64 med AVX2-stöd — riktmärken visar 2–4x ökad genomströmning på stora indata. För vardaglig avkodning av API-svar (några hundra bytes åt gången), håll dig till standardbiblioteket.
Avkoda Base64-JWT-payload i Go
JWT-inspektion dyker upp i nästan varje backend-tjänst. I min erfarenhet kokar de flesta felsökningssessioner ner till “vad är det egentligen i den här token?” — och det kan du besvara utan att dra in ett komplett JWT-bibliotek. Token har tre Base64url-kodade segment separerade med punkter. Det mellersta segmentet är den payload du faktiskt bryr dig om:
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"log"
"strings"
)
type JWTPayload struct {
Subject string `json:"sub"`
Issuer string `json:"iss"`
Expiry int64 `json:"exp"`
Roles []string `json:"roles"`
}
func decodeJWTPayload(token string) (*JWTPayload, error) {
parts := strings.Split(token, ".")
if len(parts) != 3 {
return nil, fmt.Errorf("invalid JWT: expected 3 segments, got %d", len(parts))
}
// JWT uses RawURLEncoding — URL-safe alphabet, no = padding
raw, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil {
return nil, fmt.Errorf("decode payload: %w", err)
}
var payload JWTPayload
if err := json.Unmarshal(raw, &payload); err != nil {
return nil, fmt.Errorf("unmarshal payload: %w", err)
}
return &payload, nil
}
func main() {
token := "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c3ItNDQyIiwiaXNzIjoiYXV0aC5leGFtcGxlLmNvbSIsImV4cCI6MTc0MTk1NjgwMCwicm9sZXMiOlsiYWRtaW4iLCJhdWRpdG9yIl19.SIGNATURE"
payload, err := decodeJWTPayload(token)
if err != nil {
log.Fatalf("jwt: %v", err)
}
fmt.Printf("Subject: %s\n", payload.Subject)
fmt.Printf("Issuer: %s\n", payload.Issuer)
fmt.Printf("Roles: %v\n", payload.Roles)
// Subject: usr-442
// Issuer: auth.example.com
// Roles: [admin auditor]
}Vanliga misstag
Jag har stött på alla fyra i riktiga kodgranskningar — de första två dyker upp nästan varje gång någon integrerar en ny autentiseringsleverantör.
Problem: JWT-tokens och OAuth-tokens använder det URL-säkra Base64-alfabetet (- och _). Skickar du dem till StdEncoding.DecodeString misslyckas det med 'illegal base64 data'.
Lösning: Kontrollera indatakällan: tokens från autentiseringssystem använder RawURLEncoding; binärbilagor använder StdEncoding.
// JWT header — URL-safe, no padding token := "eyJhbGciOiJSUzI1NiJ9" decoded, err := base64.StdEncoding.DecodeString(token) // err: illegal base64 data at input byte 19
// JWT header — correct encoding
token := "eyJhbGciOiJSUzI1NiJ9"
decoded, err := base64.RawURLEncoding.DecodeString(token)
// decoded: {"alg":"RS256"}
// err: nilProblem: Decode skriver in i en förallokerad buffer och returnerar antalet bytes som faktiskt skrevs. DecodedLen returnerar ett övre gränsvärde, så buffertens svans kan innehålla skräpbytes.
Lösning: Skär alltid ut resultatet med dst[:n] — inte dst[:len(dst)].
dst := make([]byte, base64.StdEncoding.DecodedLen(len(src))) base64.StdEncoding.Decode(dst, src) fmt.Println(string(dst)) // may include trailing zero bytes
dst := make([]byte, base64.StdEncoding.DecodedLen(len(src)))
n, err := base64.StdEncoding.Decode(dst, src)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(dst[:n])) // correct — only the decoded bytesProblem: Base64-strängar kopierade från terminaler, e-post eller konfigurationsfiler har ofta avslutande radbrytningar eller mellanslag. Skickas de direkt till DecodeString misslyckas det vid blankstegstecknet.
Lösning: Anropa strings.TrimSpace (och strings.ReplaceAll för inbäddade radbrytningar) innan avkodning.
// Value read from a config file with a trailing newline encoded := "c2VydmljZV9rZXk6eEtNcDI=\n" decoded, err := base64.StdEncoding.DecodeString(encoded) // err: illegal base64 data at input byte 24
encoded := "c2VydmljZV9rZXk6eEtNcDI=\n" cleaned := strings.TrimSpace(encoded) decoded, err := base64.StdEncoding.DecodeString(cleaned) // decoded: "service_key:xKMp2" // err: nil
Problem: Att anropa string(decoded) på binärdata (bilder, komprimerade payloads) producerar ogiltiga UTF-8-strängar. Go-strängar kan hålla godtyckliga bytes, men vissa operationer kan förvränga innehållet.
Lösning: Håll binärdata som []byte genom hela din pipeline. Anropa bara string(decoded) när det avkodade innehållet garanterat är text.
decoded, _ := base64.StdEncoding.DecodeString(pngBase64)
// Treating binary PNG as a string loses data
imageStr := string(decoded)
os.WriteFile("image.png", []byte(imageStr), 0644) // may corruptdecoded, err := base64.StdEncoding.DecodeString(pngBase64)
if err != nil {
log.Fatal(err)
}
// Write bytes directly — no string conversion
os.WriteFile("image.png", decoded, 0644)Metodjämförelse
Alla varianter ingår i standardbiblioteket — inga externa beroenden för någon av dessa.
För JWT-tokens och OAuth-flöden: RawURLEncoding. För e-postbilagor och MIME-data: StdEncoding. För stora binärfiler från disk eller nätverk: omslut en läsare med base64.NewDecoder — det håller minnesanvändningen konstant oavsett filstorlek. Behöver du ett anpassat alfabet? base64.NewEncoding(alphabet) skapar ett nytt kodningsobjekt för udda användningsfall.
För snabba engångskontroller under utveckling är den online Base64 Decoder snabbare än att starta ett Go-program.
Vanliga frågor
Hur avkodar jag en Base64-sträng i Go?
Importera encoding/base64 och anropa base64.StdEncoding.DecodeString(s). Den returnerar ([]byte, error) — kontrollera alltid felet. Om strängen använder URL-säkra tecken (- och _ istället för + och /), använd base64.URLEncoding.DecodeString istället. För JWT-tokens och de flesta moderna API:er är RawURLEncoding (utan utfyllnad) det rätta valet.
package main
import (
"encoding/base64"
"fmt"
"log"
)
func main() {
encoded := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
decoded, err := base64.RawURLEncoding.DecodeString(encoded)
if err != nil {
log.Fatalf("decode: %v", err)
}
fmt.Println(string(decoded))
// {"alg":"HS256","typ":"JWT"}
}Vad är skillnaden mellan StdEncoding och URLEncoding i Go?
StdEncoding använder det vanliga Base64-alfabetet med tecknen + och / samt =-utfyllnad — definierat i RFC 4648 §4. URLEncoding byter ut + mot - och / mot _, vilket gör utdatan säker i URL:er och HTTP-headers utan procentkodning — definierat i RFC 4648 §5. Använd URLEncoding för JWT-tokens, OAuth-tokens och all data som bäddas in i frågesträngar.
package main
import (
"encoding/base64"
"fmt"
)
func main() {
// Standard: may contain + / and = characters
std := base64.StdEncoding.EncodeToString([]byte("hello/world"))
fmt.Println(std) // "aGVsbG8vd29ybGQ="
// URL-safe: replaces + with - and / with _
url := base64.URLEncoding.EncodeToString([]byte("hello/world"))
fmt.Println(url) // "aGVsbG8vd29ybGQ=" (same — diff shows with different bytes)
// JWT headers never have padding — use RawURLEncoding
raw := base64.RawURLEncoding.EncodeToString([]byte("hello/world"))
fmt.Println(raw) // "aGVsbG8vd29ybGQ" (no trailing =)
}Hur åtgärdar jag "illegal base64 data"-fel i Go?
Det här felet innebär att indata innehåller tecken utanför det förväntade alfabetet, eller att utfyllnaden är fel. Tre vanliga orsaker: du använder StdEncoding på URL-säker indata (byt till URLEncoding), du använder en kodare med utfyllnad på indata utan utfyllnad (byt till RawStdEncoding/RawURLEncoding), eller att det finns avslutande blanksteg/radbrytningar. Ta bort blanksteg med strings.TrimSpace innan avkodning.
package main
import (
"encoding/base64"
"fmt"
"log"
"strings"
)
func main() {
// Input from a webhook payload — has newlines stripped from wire format
raw := " aGVsbG8gd29ybGQ= \n"
cleaned := strings.TrimSpace(raw)
decoded, err := base64.StdEncoding.DecodeString(cleaned)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(decoded)) // hello world
}Hur strömavkodar jag en stor Base64-kodad fil i Go?
Använd base64.NewDecoder(base64.StdEncoding, reader) som omsluter valfri io.Reader och avkodar löpande. Skicka det genom io.Copy för att skriva till destinationen utan att buffra hela filen i minnet. Det här är standardmönstret för att avkoda Base64-kodade binärbilagor eller stora datapayloads.
package main
import (
"encoding/base64"
"io"
"log"
"os"
)
func main() {
src, err := os.Open("attachment.b64")
if err != nil {
log.Fatal(err)
}
defer src.Close()
dst, err := os.Create("attachment.bin")
if err != nil {
log.Fatal(err)
}
defer dst.Close()
decoder := base64.NewDecoder(base64.StdEncoding, src)
io.Copy(dst, decoder)
}Kan jag avkoda en Base64-JWT-payload i Go utan ett JWT-bibliotek?
Ja. En JWT består av tre Base64url-kodade segment åtskilda av punkter. Dela på "." och avkoda det andra segmentet (index 1) med base64.RawURLEncoding.DecodeString — JWT-headers och payloads använder det URL-säkra alfabetet utan utfyllnad. Signatursegmentet (index 2) är binärt och behövs vanligtvis bara för verifiering.
package main
import (
"encoding/base64"
"fmt"
"log"
"strings"
)
func main() {
token := "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c3ItOTAxIiwicm9sZSI6ImFkbWluIn0.SIG"
parts := strings.Split(token, ".")
if len(parts) < 2 {
log.Fatal("invalid JWT format")
}
payload, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil {
log.Fatalf("decode payload: %v", err)
}
fmt.Println(string(payload))
// {"sub":"usr-901","role":"admin"}
}Vilken kodning ska jag använda för att avkoda Base64-data från ett HTTP API-svar?
Kontrollera API-dokumentationen eller inspektera den kodade strängen. Om den innehåller + eller / och slutar med =, använd StdEncoding. Om den använder - och _ utan =, använd RawURLEncoding. Vid osäkerhet, prova RawURLEncoding först — de flesta moderna API:er (OAuth2, JWT, Google Cloud, AWS) använder URL-säker Base64 utan utfyllnad.
package main
import (
"encoding/base64"
"strings"
)
// Detect encoding variant from the encoded string
func decodeAPIPayload(encoded string) ([]byte, error) {
// URL-safe characters without padding — common in modern APIs
if !strings.Contains(encoded, "+") && !strings.Contains(encoded, "/") {
return base64.RawURLEncoding.DecodeString(encoded)
}
// Standard Base64 with padding
return base64.StdEncoding.DecodeString(encoded)
}Relaterade verktyg
- Base64 Encoder — koda binärdata eller text till Base64 i webbläsaren, användbart för att generera testfixtures att klistra in i dina Go-enhetstester.
- JWT Decoder — dela och avkoda alla tre JWT-segment på en gång, med fält-för-fält payload-inspektion — ingen Go-kod behövs när du bara behöver läsa en token under felsökning.
- URL Decoder — procentavkoda URL-kodade strängar, praktiskt när API-svar blandar Base64url-data med procentkodade frågeparametrar.
- JSON Formatter — efter att du avkodat en Base64-JWT-payload eller ett API-svar, klistra in JSON:en här för att formatera och validera strukturen direkt.