Base64 URL-safe
URL 안전 Base64(Base64url) 인코딩 및 디코딩
일반 텍스트
Base64
Base64url 인코딩이란?
Base64url은 URL, 파일명, 표준 Base64 문자인 +와 /가 문제를 일으키는 기타 컨텍스트에서 사용하도록 설계된 Base64 인코딩의 변형입니다. RFC 4648 섹션 5에 정의된 Base64url은 +를 -(하이픈)으로, /를 _(언더스코어)로 대체하고 후행 = 패딩 문자를 생략합니다. 결과 문자열은 추가적인 퍼센트 인코딩 없이 URL 쿼리 파라미터, 파일명, HTTP 헤더에 직접 삽입할 수 있습니다.
표준 Base64(RFC 4648 섹션 4)는 64개의 문자를 사용합니다: A-Z, a-z, 0-9, +, /. +와 / 문자는 URL에서 예약된 문자입니다: +는 쿼리 문자열(application/x-www-form-urlencoded)에서 공백으로 해석되고, /는 경로 구분자입니다. 따라서 URL 내에서 표준 Base64를 사용하려면 이 문자들을 퍼센트 인코딩(%2B, %2F)해야 하므로 문자열 길이가 늘어나고 가독성이 떨어집니다. Base64url은 처음부터 URL에 안전한 문자를 사용하여 이 문제를 완전히 해소합니다.
Base64url의 가장 대표적인 사용 사례는 JSON Web Token(JWT)입니다. JWT의 세 세그먼트 — 헤더, 페이로드, 서명 — 모두 Base64url로 인코딩됩니다. OAuth 2.0 PKCE code verifier, WebAuthn 챌린지 값, 그리고 많은 API 토큰 체계도 Base64url에 의존합니다. 인증, 권한 부여, 또는 암호화 데이터 교환을 다루는 개발자라면 이 인코딩 방식을 이해하는 것이 필수적입니다.
이 Base64url 도구를 사용하는 이유
브라우저에서 직접 Base64url과 텍스트 또는 바이너리 데이터 간을 변환합니다. 인코딩과 디코딩 모두 지원하며, 패딩 및 문자 대체를 자동으로 처리합니다. JWT 토큰을 디버깅하거나, PKCE 코드 챌린지를 생성하거나, URL 안전 식별자를 구축하는 경우에도 이 도구는 브라우저에서 로컬로 모든 처리를 수행하므로 지연 없이 서버 왕복 없이 즉시 결과를 얻을 수 있습니다.
Base64url 활용 사례
표준 Base64 vs Base64url
Base64url은 표준 Base64와 정확히 세 가지 면에서 다릅니다. 인코딩 알고리즘은 동일하며 — 알파벳과 패딩 동작만 변경됩니다:
| 특징 | 표준 (RFC 4648 §4) | Base64url (RFC 4648 §5) |
|---|---|---|
| Index 62 | + | - |
| Index 63 | / | _ |
| Padding | = (required) | Omitted |
이 세 가지 차이점 덕분에 표준 Base64와 Base64url 간 변환은 간단합니다: +를 -로, /를 _로 교체하고 후행 = 문자를 제거합니다. 반대로는 -를 +로, _를 /로 교체하고 길이가 4의 배수가 되도록 패딩을 다시 추가합니다. 대부분의 언어는 네이티브 Base64url 지원을 제공하므로 수동 변환이 불필요합니다. 두 변환 모두 완전히 역변환 가능하며 손실이 없어 원본 바이트 시퀀스를 정확히 보존합니다. 이 상호 운용성은 RFC 4648에 의해 보장됩니다.
인코딩 비교 표
아래 표는 표준 Base64와 Base64url로 인코딩된 동일한 입력을 보여줍니다. URL 안전 변형에서 패딩 문자(=)가 제거되고 +와 /가 -와 _로 대체되는 것을 확인하세요:
| 입력 | 표준 Base64 | Base64url (패딩 없음) |
|---|---|---|
| Hello | SGVsbG8= | SGVsbG8 |
| A | QQ== | |
| 1+1=2 | MSsxPTI= | MSsxPTI |
| subject?ref=1 | c3ViamVjdD9yZWY9MQ== | c3ViamVjdD9yZWY9MQ |
| ð (thumbs up) | 8J+RjQ== | 8J-RjQ |
코드 예제
인기 있는 언어에서 Base64url 문자열을 인코딩하고 디코딩하는 방법. 모든 예제는 URL, 파일명, HTTP 헤더에서 안전하게 사용할 수 있는 출력을 생성합니다:
// Encode to Base64url
function toBase64url(str) {
return btoa(unescape(encodeURIComponent(str)))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '')
}
toBase64url('Hello!') // → "SGVsbG8h"
// Decode from Base64url
function fromBase64url(b64url) {
const b64 = b64url.replace(/-/g, '+').replace(/_/g, '/')
const pad = (4 - b64.length % 4) % 4
return decodeURIComponent(escape(atob(b64 + '='.repeat(pad))))
}
fromBase64url('SGVsbG8h') // → "Hello!"// Native base64url support since Node 15.7
const encoded = Buffer.from('Hello!').toString('base64url')
// → "SGVsbG8h"
const decoded = Buffer.from('SGVsbG8h', 'base64url').toString()
// → "Hello!"
// Decode a JWT payload
const jwt = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0...'
const payload = JSON.parse(Buffer.from(jwt.split('.')[1], 'base64url').toString())
// → { sub: "1234567890" }import base64
# Encode to Base64url (no padding)
encoded = base64.urlsafe_b64encode(b'Hello!').rstrip(b'=').decode()
# → "SGVsbG8h"
# Decode from Base64url (re-add padding)
def b64url_decode(s: str) -> bytes:
s += '=' * (4 - len(s) % 4) # restore padding
return base64.urlsafe_b64decode(s)
b64url_decode('SGVsbG8h') # → b'Hello!'package main
import (
"encoding/base64"
"fmt"
)
func main() {
// Encode to Base64url (no padding)
encoded := base64.RawURLEncoding.EncodeToString([]byte("Hello!"))
fmt.Println(encoded) // → "SGVsbG8h"
// Decode from Base64url
decoded, _ := base64.RawURLEncoding.DecodeString("SGVsbG8h")
fmt.Println(string(decoded)) // → "Hello!"
}