Base64 Encoder & DecoderConvert payloads without exposing raw text to third-party tools
Flip between plain text and Base64 while debugging headers, credentials, and small config fragments. Conversion runs in this browser tab; OpsecForge does not send the pasted text to a tool-processing backend. The page itself still loads site resources and aggregate analytics.
Encode UTF-8 text as standard Base64 or unpadded Base64URL, then decode it back with strict UTF-8 validation.
Encoding examples you can check
Base64 turns every 3 bytes into 4 characters. A final group of 2 bytes is padded with one =, and a group of 1 byte with two, which is why a becomes YQ==. Base64URL replaces + and / with - and _; this tool also drops the padding in that mode. Paste any input below into Encode mode to reproduce the row.
| Input text | Standard Base64 | Base64URL |
|---|---|---|
Hello, World! | SGVsbG8sIFdvcmxkIQ== | SGVsbG8sIFdvcmxkIQ |
a | YQ== | YQ |
ab | YWI= | YWI |
abc | YWJj | YWJj |
héllo | aMOpbGxv | aMOpbGxv |
<<???>> | PDw/Pz8+Pg== | PDw_Pz8-Pg |
Text is encoded as UTF-8
The tool converts text to UTF-8 bytes first, so é is the two bytes C3 A9 and héllo encodes to aMOpbGxv. The browser's bare btoa() works on Latin-1 characters instead: btoa("é") returns 6Q== (one byte, E9), and btoa("€") throws InvalidCharacterError. If two systems disagree on the same string, compare the bytes they encoded.
Two places you meet Base64 every day
A JWT header is Base64URL without padding. Decode eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 in Base64URL mode and you get {"alg":"HS256","typ":"JWT"}. HTTP Basic authentication Base64-encodes user:password: RFC 7617's example Aladdin:open sesame becomes Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==. Base64 is a transport encoding, not encryption; anyone who sees the header can decode it.
When decoding fails
| Input | Mode | Result | Fix |
|---|---|---|---|
SGVsbG8== | Standard | Invalid Base64 input. | Seven characters need exactly one =; remove the extra one. |
SGVsb | Standard | Invalid Base64 input. | A length of 1 mod 4 cannot occur in valid Base64; the string was cut off. |
PDw_Pz8-Pg | Standard | Invalid Base64 input. | It contains - and _, so it is Base64URL; switch the variant. |
PDw/Pz8+Pg== | Base64URL | Invalid Base64URL input. | It contains + and /; use the Standard variant. |
/w== | Standard | Decoded bytes are not valid UTF-8 text. | The byte FF is not text. Binary data (images, keys) should be decoded to a file instead. |
SGVsbG8 | Standard | Hello | Missing padding is accepted; whitespace and line breaks are ignored. |
The same conversion in code
btoa(String.fromCharCode(...new TextEncoder().encode('héllo'))) // 'aMOpbGxv'
Buffer.from('<<???>>').toString('base64url') // 'PDw_Pz8-Pg' (Node.js)import base64
base64.b64encode('héllo'.encode()).decode() # 'aMOpbGxv'
base64.urlsafe_b64encode(b'<<???>>').rstrip(b'=').decode() # 'PDw_Pz8-Pg'printf 'Hello, World!' | base64 # SGVsbG8sIFdvcmxkIQ==
# GNU base64 wraps output at 76 characters; add -w0 to keep one line- Why are my encoded strings longer than the input?
- Four output characters carry three input bytes, so Base64 text is about a third larger than the data, plus any padding.