Go encoding/base64 디코딩 가이드

·Systems Engineer·검토자Hana Nováková·게시일

무료 Base64 디코더을 브라우저에서 직접 사용하세요 — 설치 불필요.

Base64 디코더 온라인으로 사용하기 →

Go에서 Base64 디코딩은 JWT 검사, 바이너리 파일 첨부, 클라우드 서비스의 API 페이로드 처리 등 매우 빈번하게 필요합니다. Go의 표준 encoding/base64패키지는 이 모든 경우를 처리하지만, 잘못된 인코딩 변형(표준 vs URL 안전, 패딩 있음 vs 없음)을 선택하는 것이 “illegal base64 data” 에러의 가장 흔한 원인입니다. 이 가이드는 StdEncoding, URLEncoding, RawURLEncoding, base64.NewDecoder를 이용한 스트리밍 디코딩, JWT 페이로드 검사, 그리고 처음에 거의 모두가 실수하는 네 가지 흔한 오류를 다룹니다. 브라우저에서 간편하게 디코딩하려면 ToolDeck's Base64 decoder 를 사용하면 코드 한 줄 없이 즉시 처리할 수 있습니다.

  • encoding/base64는 Go 표준 라이브러리에 포함되어 있으므로 go get이 필요 없습니다
  • JWT 토큰과 대부분의 최신 API에는 RawURLEncoding을 사용하세요 (패딩 없음, URL 안전 알파벳)
  • StdEncoding은 + 및 /와 = 패딩을 사용하고, URLEncoding은 - 및 _로 대체하되 패딩은 유지합니다
  • base64.NewDecoder는 모든 io.Reader를 래핑하여 메모리에 로드하지 않고 스트리밍 디코딩을 지원합니다
  • 반환된 에러를 항상 확인하세요 — 잘못된 패딩과 잘못된 알파벳은 illegal base64 data를 발생시킵니다

Base64 디코딩이란?

Base64 인코딩은 64개의 출력 가능한 문자(A–Z, a–z, 0–9, 그리고 두 개의 추가 문자)를 사용하여 바이너리 데이터를 ASCII 텍스트로 표현합니다. 디코딩은 이 과정을 역으로 수행하여 ASCII 표현을 원래 바이트로 변환합니다. 4개의 Base64 문자는 정확히 3바이트로 디코딩됩니다. 이 방식이 존재하는 이유는 많은 전송 계층(이메일, HTTP 헤더, JSON 필드)이 원시 바이너리가 아닌 텍스트를 위해 설계되어 있기 때문입니다. 다음은 왕복 변환이 어떻게 이루어지는지 보여줍니다:

Go 1.21+
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
}

encoding/base64로 Go에서 Base64 디코딩하기

encoding/base64 패키지는 Go와 함께 제공되므로 외부 의존성이 없습니다. 패키지 수준 변수로 네 가지 사전 정의된 인코딩 변형을 제공합니다. 문자열 입력에 가장 많이 사용되는 함수는 DecodeString으로, 바이트 슬라이스와 에러를 반환합니다.

Go 1.21+
package main

import (
	"encoding/base64"
	"fmt"
	"log"
)

func main() {
	// Standard Base64 — the alphabet uses + and / with = padding
	encoded := "eyJob3N0IjoiZGItcHJvZC51cy1lYXN0LTEiLCJwb3J0Ijo1NDMyfQ=="
	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}
}

Decode 메서드는 문자열 대신 바이트 슬라이스를 대상으로 하며, 미리 할당된 대상 버퍼에 결과를 씁니다. 버퍼 크기를 올바르게 지정해야 합니다 — 최대 크기를 얻으려면 base64.StdEncoding.DecodedLen(len(src))을 사용하세요 (패딩으로 인해 실제 디코딩된 길이보다 몇 바이트 클 수 있습니다).

Go 1.21+
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은 정확한 길이가 아닌 상한값을 반환합니다. 결과를 올바르게 슬라이싱하려면 항상 Decode의 반환값 n을 사용하세요: dst[:n].

StdEncoding vs URLEncoding — 올바른 변형 선택하기

대부분의 혼란이 여기서 발생합니다. Go의 encoding/base64는 네 가지 인코딩 객체를 제공하며, 잘못된 것을 선택하면 반드시 에러가 발생합니다. 차이는 두 가지로 귀결됩니다: 알파벳과 패딩.

Go 1.21+
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"}
}

네 가지 변형을 간단히 정리하면:

함수 / 메서드
인코딩
패딩 필요 여부
반환값
base64.StdEncoding.DecodeString(s)
표준 (+, /)
필요 (=)
([]byte, error)
base64.URLEncoding.DecodeString(s)
URL 안전 (-, _)
필요 (=)
([]byte, error)
base64.RawStdEncoding.DecodeString(s)
표준 (+, /)
불필요
([]byte, error)
base64.RawURLEncoding.DecodeString(s)
URL 안전 (-, _)
불필요
([]byte, error)
base64.StdEncoding.Decode(dst, src)
표준 (+, /)
필요 (=)
(n int, error)
base64.NewDecoder(enc, r)
모든 인코딩
필요
io.Reader

경험상 원칙: JWT, OAuth 흐름, 또는 클라우드 공급자 SDK에서 온 데이터라면 RawURLEncoding을 먼저 시도하세요. 이메일 첨부 파일이나 구형 웹 폼에서 온 데이터라면 StdEncoding을 시도하세요. 에러 메시지는 항상 디코딩이 실패한 정확한 바이트 위치를 알려줍니다.

파일 및 API 응답에서 Base64 디코딩하기

Base64로 인코딩된 파일 읽기

바이너리 파일(이미지, PDF, 인증서)이 디스크에 Base64로 인코딩되어 저장되는 경우가 있습니다. 파일을 읽고, 후행 공백을 제거한 후 디코딩하세요:

Go 1.21+
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))
}

API JSON 응답에서 Base64 필드 디코딩하기

클라우드 API는 JSON 내부에 바이너리 데이터(암호화 키, 서명된 블롭, 썸네일)를 Base64 문자열로 반환하는 경우가 많습니다. JSON을 먼저 언마샬한 후 대상 필드를 디코딩하세요:

Go 1.21+
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)로 에러를 래핑하세요. encoding/base64의 원본 에러 메시지에는 실패 위치의 바이트 오프셋이 포함되어 있어 디버깅에 유용합니다.

대용량 Base64 인코딩 파일 스트리밍

os.ReadFile로 500MB Base64 인코딩 파일을 메모리에 로드한 후 DecodeString을 호출하면 약 750MB의 RAM을 사용합니다(인코딩된 문자열과 디코딩된 바이트 합산). base64.NewDecoder는 모든 io.Reader를 래핑하여 청크 단위로 디코딩하므로 메모리 사용량이 거의 일정하게 유지됩니다. io.Copy와 결합하면 깔끔한 스트리밍 파이프라인을 만들 수 있습니다:

Go 1.21+
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는 줄바꿈 없는 연속적인 Base64 데이터를 기대합니다. 소스 파일에 줄바꿈이 있는 경우(PEM 및 MIME 인코딩 파일에 흔히 있음), 스트리밍 전에 줄 제거 리더로 소스 리더를 래핑하거나 파일을 전처리하여 줄바꿈을 제거하세요.

커맨드라인에서 Base64 디코딩하기

대부분의 Go 개발자는 디버깅 시 커맨드라인을 먼저 사용합니다. macOS 및 Linux 시스템에는 base64가 기본으로 포함되어 있으며, Windows에서는 PowerShell에 내장된 동등한 기능이 있습니다. API 페이로드를 빠르게 확인할 때는 Go 스크립트를 작성하는 것보다 빠릅니다.

bash
# Decode a Base64 string (Linux / macOS)
echo "eyJob3N0IjoiZGItcHJvZCIsInBvcnQiOjU0MzJ9" | base64 --decode
# {"host":"db-prod","port":5432}

# Decode and pretty-print with jq (pipe the JSON output)
echo "eyJob3N0IjoiZGItcHJvZCIsInBvcnQiOjU0MzJ9" | base64 --decode | jq .
# {
#   "host": "db-prod",
#   "port": 5432
# }

# Decode a Base64-encoded file to binary
base64 --decode < encrypted_payload.b64 > encrypted_payload.bin

# macOS uses -D flag instead of --decode
echo "c2VjcmV0LXRva2Vu" | base64 -D

아무 도구도 설치하지 않고 JWT 토큰을 검사하려면 토큰을 ToolDeck's Base64 decoder 에 붙여넣고 — 점으로 분할한 후 각 부분을 디코딩하세요.

고성능 대안: encoding/base64는 이미 빠릅니다

Python에서 orjson vs json이 의미 있는 성능 차이를 만드는 것과 달리, Go의 encoding/base64는 이미 어셈블리 최적화가 되어 있으며 대부분의 워크로드에서 충분히 빠릅니다. 다만 타이트한 루프에서 수백만 건의 레코드를 처리하는 경우라면 filippo.io/base64가 동일한 API로 SIMD 가속 디코딩을 제공합니다.

bash
go get filippo.io/base64
Go 1.21+
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}
}

성능 향상은 AVX2를 지원하는 amd64에서 가장 두드러집니다 — 벤치마크에 따르면 대용량 입력에서 처리량이 2–4배 향상됩니다. 일반적인 API 응답 디코딩(한 번에 수백 바이트)에는 표준 라이브러리를 사용하는 것이 좋습니다.

Go에서 Base64 JWT 페이로드 디코딩하기

JWT 검사는 거의 모든 백엔드 서비스에서 필요합니다. 제 경험상 대부분의 디버깅 세션은 “이 토큰에 실제로 무엇이 들어 있나?”로 귀결됩니다 — 그리고 전체 JWT 라이브러리 없이도 답을 찾을 수 있습니다. 토큰은 점으로 구분된 세 개의 Base64url 인코딩 세그먼트로 구성됩니다. 중간 세그먼트가 실제로 필요한 페이로드입니다:

Go 1.21+
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]
}

흔한 실수

실제 코드 리뷰에서 이 네 가지를 모두 경험했습니다 — 특히 처음 두 가지는 새로운 인증 공급자를 통합할 때마다 거의 항상 나타납니다.

URL 안전 입력에 StdEncoding 사용하기

문제: JWT 토큰과 OAuth 토큰은 URL 안전 Base64 알파벳(- 및 _)을 사용합니다. 이를 StdEncoding.DecodeString에 전달하면 'illegal base64 data'로 실패합니다.

해결책: 입력 소스를 확인하세요: 인증 시스템의 토큰에는 RawURLEncoding을 사용하고, 바이너리 첨부 파일에는 StdEncoding을 사용하세요.

Before · Go
After · Go
// 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: nil
Decode의 n 반환값 무시하기

문제: Decode는 미리 할당된 버퍼에 쓰고 실제로 쓴 바이트 수를 반환합니다. DecodedLen은 상한값을 반환하므로 버퍼 끝에 가비지 바이트가 포함될 수 있습니다.

해결책: 결과를 항상 dst[:n]으로 슬라이싱하세요 — dst[:len(dst)]가 아닙니다.

Before · Go
After · Go
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 bytes
디코딩 전 공백 제거 누락

문제: 터미널, 이메일, 설정 파일에서 복사한 Base64 문자열에는 종종 후행 줄바꿈이나 공백이 있습니다. 이를 DecodeString에 직접 전달하면 공백 문자 위치에서 실패합니다.

해결책: 디코딩 전에 strings.TrimSpace(임베디드 줄바꿈에는 strings.ReplaceAll도 함께)를 호출하세요.

Before · Go
After · Go
// 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
디코딩된 바이트를 문자열로 잘못 저장하기

문제: 바이너리 데이터(이미지, 압축 페이로드)에 string(decoded)를 호출하면 유효하지 않은 UTF-8 문자열이 생성됩니다. Go 문자열은 임의의 바이트를 저장할 수 있지만 일부 연산은 내용을 손상시킬 수 있습니다.

해결책: 파이프라인 전체에서 바이너리 데이터를 []byte로 유지하세요. 디코딩된 내용이 텍스트임이 보장될 때만 string(decoded)를 호출하세요.

Before · Go
After · Go
decoded, _ := base64.StdEncoding.DecodeString(pngBase64)
// Treating binary PNG as a string loses data
imageStr := string(decoded)
os.WriteFile("image.png", []byte(imageStr), 0644) // may corrupt
decoded, err := base64.StdEncoding.DecodeString(pngBase64)
if err != nil {
    log.Fatal(err)
}
// Write bytes directly — no string conversion
os.WriteFile("image.png", decoded, 0644)

메서드 비교

모든 변형은 표준 라이브러리에 포함되어 있으므로 외부 의존성이 없습니다.

메서드
입력 타입
인코딩 변형
스트리밍
커스텀 알파벳
커스텀 패딩
설치 필요
StdEncoding.DecodeString
string
표준
불필요 (stdlib)
URLEncoding.DecodeString
string
URL 안전
불필요 (stdlib)
RawStdEncoding.DecodeString
string
표준 (패딩 없음)
불필요 (stdlib)
RawURLEncoding.DecodeString
string
URL 안전 (패딩 없음)
불필요 (stdlib)
StdEncoding.Decode
[]byte
표준
불필요 (stdlib)
base64.NewDecoder
io.Reader
모두
불필요 (stdlib)
encoding/base64 + NewEncoding
string
커스텀 알파벳
불필요 (stdlib)

JWT 토큰과 OAuth 흐름에는: RawURLEncoding. 이메일 첨부 파일과 MIME 데이터에는: StdEncoding. 디스크나 네트워크에서 오는 대용량 바이너리 파일에는: 리더를 base64.NewDecoder로 래핑하세요 — 파일 크기에 관계없이 메모리 사용을 일정하게 유지합니다. 커스텀 알파벳이 필요하다면? base64.NewEncoding(alphabet)으로 특수한 사용 사례를 위한 새로운 인코딩 객체를 만들 수 있습니다.

개발 중 빠른 일회성 확인이 필요할 때는 온라인 Base64 decoder 가 Go 프로그램을 실행하는 것보다 빠릅니다.

자주 묻는 질문

Go에서 Base64 문자열을 어떻게 디코딩하나요?

encoding/base64를 임포트하고 base64.StdEncoding.DecodeString(s)를 호출하세요. ([]byte, error)를 반환하므로 에러를 반드시 확인해야 합니다. 문자열에 URL 안전 문자(+ 대신 -, / 대신 _)가 포함되어 있다면 base64.URLEncoding.DecodeString을 대신 사용하세요. JWT 토큰과 대부분의 최신 API에는 RawURLEncoding(패딩 없음)이 올바른 선택입니다.

Go 1.21+
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"}
}

Go에서 StdEncoding과 URLEncoding의 차이점은 무엇인가요?

StdEncoding은 + 및 / 문자와 = 패딩을 사용하는 표준 Base64 알파벳을 사용합니다 — RFC 4648 §4에 정의되어 있습니다. URLEncoding은 +를 -로, /를 _로 대체하여 퍼센트 인코딩 없이 URL과 HTTP 헤더에서 안전하게 사용할 수 있게 합니다 — RFC 4648 §5에 정의되어 있습니다. JWT 토큰, OAuth 토큰, 쿼리 문자열에 포함된 데이터에는 URLEncoding을 사용하세요.

Go 1.21+
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 =)
}

Go에서 "illegal base64 data" 에러를 어떻게 수정하나요?

이 에러는 입력에 예상된 알파벳 범위를 벗어난 문자가 있거나 패딩이 잘못되었음을 의미합니다. 세 가지 주요 원인: URL 안전 입력에 StdEncoding 사용(URLEncoding으로 교체), 패딩 없는 입력에 패딩 인코더 사용(RawStdEncoding/RawURLEncoding으로 교체), 또는 후행 공백/줄바꿈. 디코딩 전에 strings.TrimSpace로 공백을 제거하세요.

Go 1.21+
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
}

Go에서 대용량 Base64 인코딩 파일을 스트림으로 디코딩하는 방법은?

base64.NewDecoder(base64.StdEncoding, reader)를 사용하면 모든 io.Reader를 래핑하여 실시간으로 디코딩합니다. io.Copy를 통해 파이프하면 전체 파일을 메모리에 버퍼링하지 않고 대상에 쓸 수 있습니다. 이는 Base64로 인코딩된 바이너리 첨부 파일이나 대용량 데이터 페이로드를 디코딩하는 표준 패턴입니다.

Go 1.21+
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)
}

Go에서 JWT 라이브러리 없이 Base64 JWT 페이로드를 디코딩할 수 있나요?

네. JWT는 점으로 구분된 세 개의 Base64url 인코딩 세그먼트입니다. "."로 분할하고 두 번째 세그먼트(인덱스 1)를 base64.RawURLEncoding.DecodeString으로 디코딩하세요 — JWT 헤더와 페이로드는 URL 안전 알파벳과 패딩 없음을 사용합니다. 서명 세그먼트(인덱스 2)는 바이너리이며 일반적으로 검증 시에만 필요합니다.

Go 1.21+
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"}
}

HTTP API 응답에서 받은 Base64 데이터를 디코딩할 때 어떤 인코딩을 사용해야 하나요?

API 문서를 확인하거나 인코딩된 문자열을 살펴보세요. + 또는 / 문자를 포함하고 =로 끝난다면 StdEncoding을 사용하세요. = 없이 - 및 _ 문자를 사용한다면 RawURLEncoding을 사용하세요. 확실하지 않은 경우 RawURLEncoding을 먼저 시도하세요 — 대부분의 최신 API(OAuth2, JWT, Google Cloud, AWS)는 패딩 없는 URL 안전 Base64를 사용합니다.

Go 1.21+
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)
}

관련 도구

  • Base64 Encoder — 브라우저에서 바이너리 데이터나 텍스트를 Base64로 인코딩하여 Go 유닛 테스트에 붙여넣을 테스트 픽스처를 생성하는 데 유용합니다.
  • JWT Decoder — 세 개의 JWT 세그먼트를 한 번에 분할 및 디코딩하고 페이로드를 필드별로 검사합니다 — 디버깅 중 토큰을 읽기만 할 때는 Go 코드가 필요하지 않습니다.
  • URL Decoder — URL 인코딩된 문자열을 퍼센트 디코딩합니다. API 응답에서 Base64url 데이터와 퍼센트 인코딩된 쿼리 파라미터가 혼합되어 있을 때 유용합니다.
  • JSON Formatter — Base64 JWT 페이로드나 API 응답을 디코딩한 후, JSON을 여기에 붙여넣어 구조를 즉시 보기 좋게 출력하고 유효성을 검사하세요.
다른 언어로도 제공됩니다:JavaScriptPythonJavaC#
JO
James OkaforSystems Engineer

James is a systems engineer and Go enthusiast who focuses on high-performance microservices, command-line tooling, and infrastructure automation. He enjoys the simplicity and explicitness of Go and writes about building fast, reliable backend systems. When not coding he explores distributed systems concepts and contributes to open-source Go libraries.

HN
Hana Nováková기술 검토자

Hana is a backend engineer who has built production gRPC and REST services in Go for cloud-native environments. She cares deeply about API correctness, protobuf schema design, and the operational side of running Go services in Kubernetes. She writes about the Go standard library, encoding and marshalling patterns, gRPC best practices, and the subtleties of writing idiomatic Go that is easy to test and maintain.