Base64URL Encoder/Decoder
Encode and decode RFC 4648 §5 URL-safe Base64 with JWT-strict padding control — entirely on this device.
JWT segments omit '=' — accept tolerates it, require insists on it, forbid rejects it.
Same bytes, re-encoded
Press ? for shortcuts
Do it offline:$ basenc --base64url -d token.txt
How to use it
- Paste a base64url string — a JWT segment, an OAuth state value. It decodes as you type; - and _ are the grammar here, not a tolerance.
- Set the padding policy: accept decodes either form, chipping any = it saw; require insists on the trailing =; forbid enforces the JWS no-padding shape.
- Switch to Encode for the other direction — unpadded by default per RFC 7515, with a toggle that restores the =.
- Copy either row of the variants card: the same bytes as unpadded URL-safe and as padded standard Base64.
Paste a JWT header or payload segment and read it as you type — this page speaks RFC 4648 §5 base64url natively: - and _ need no switch, and a stray + or / is reported at its position. Three padding policies make the RFC 7515 rules explicit, a variants card re-encodes to standard Base64, and everything runs on this device.
How it works
The standard alphabet's + and / collide with the grammars tokens travel through — + decodes as a space in form bodies, / delimits URL paths — so RFC 4648 §5 substitutes two characters: six-bit value 62 becomes - and 63 becomes _, and nothing else changes. Both alphabets spell identical bytes, so converting between them never touches the data.
RFC 7515 §2 goes further for JSON Web Signatures, defining base64url with all trailing = omitted — no real JWT segment carries padding. The omission is arithmetic: four characters carry three bytes, so an unpadded length mod 4 leaves remainder 0, 2 or 3, and the remainder alone says whether zero, two or one = were dropped. Remainder 1 can never occur — a reliable corruption signal, reported before any bytes are produced.
Examples
eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9{"typ":"JWT",
"alg":"HS256"}The protected header from RFC 7515 appendix A.1.1, decoded byte-for-byte — carriage return, line feed and space included. Forty characters, remainder 0: no padding to restore.
<<???>>PDw_Pz8-PgStandard Base64 spells these seven bytes PDw/Pz8+Pg==; the URL-safe form swaps / for _, + for -, and drops the ==.
PDw_Pz8-Pg==<<???>>URL-safe characters with the = kept. The default policy decodes this and raises “Trailing '=' padding was accepted”; under forbid the same = is a hard error.
PDw/Pz8+Pg==<<???>>The standard spelling, decoded with accept-standard on and declared by “Standard alphabet detected (+ and / accepted)”. The variants card holds the unpadded URL-safe form to copy.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
Which padding policy matches which consumer
RFC 4648 §3.2 requires the trailing = unless the referring specification says otherwise; RFC 7515 §2 says otherwise for JWS. require validates for strict RFC 4648 decoders, forbid checks the JWT shape, accept reads both — the chip reports which form arrived.
Strictness is the feature
The sibling Base64 Decoder treats URL-safe characters as a tolerance; this page inverts that. The first + or / halts the decode at its position with a switch-alphabet hint — pass under forbid with no chips and an RFC 7515 consumer takes the string as-is.
Signature segments decode to bytes, not text
A JWT's third segment is a MAC — 32 raw bytes for HS256 — so non-UTF-8 output switches to a byte view and downloads as untouched octets. Claims and expiry belong to the JWT Decoder; here you get the raw material.
A remainder of one is unrepairable
A cleaned length of 4n+1 has no byte interpretation, so require deliberately does not ask for = there — the verdict stays “Base64 length is invalid — 1 stray character” — padding a truncated string would only disguise the damage.
Common errors
Invalid base64url: character '+' at position 13 — this looks like standard Base64; switch to the standard alphabet.- The strict pass stops at the first standard-alphabet character — here the RFC 7515 example signature transcoded to + and /. Accept-standard decodes it with a chip; the variants card offers the URL-safe row.
Padding is forbidden: character '=' at position 11 — the padding policy is set to "forbid"; remove the padding or switch the policy.- Under forbid the page is a JWS conformance check — RFC 7515 defines segments without trailing =. Delete the =, which the remainder already implies, or switch back to accept.
Base64 length is invalid — 1 stray character- A length one past a multiple of four cannot come out of any encoder in either alphabet, so no policy changes the verdict — a character was clipped, or one rode along.
Input is larger than the 16 MB limit for this tool. For bigger payloads use the CLI: basenc --base64url -d token.txt- The cap refuses rather than truncates; the pasted input stays untouched. GNU coreutils ships basenc, whose --base64url mode handles this alphabet at any size; -d decodes.
FAQ
Why do JWT segments have no = padding?
RFC 7515 §2 defines the encoding for JWS with all trailing = omitted — a bare = would need escaping in URLs and form bodies, where tokens live. Nothing is lost: length mod 4 tells any decoder how many = to put back.
Why does atob() fail on base64url strings?
atob implements only the standard alphabet and throws an InvalidCharacterError at the first - or _. Substitute + for - and / for _ before the call — or paste the value here, which also handles the UTF-8 step.
How do I convert standard Base64 to base64url?
Replace + with -, / with _, and drop the trailing =; the bytes never change; the mirror substitution converts back. The round trip is built in here — accept the offered switch, then copy the URL-safe variants row.
Can I decode a whole JWT here?
One segment at a time — dots sit outside every Base64 alphabet, so a full paste stops at the first one with a hint pointing here or to the JWT Decoder for a structured claims view. Base64url is an alphabet swap, not encryption.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Run or re-run the current direction.
- ⌘/Ctrl + S
- Download the output; binary results get a sniffed extension.
- ⌘/Ctrl + C
- Copy the output when nothing is selected.
- ⌘/Ctrl + Shift + C
- Copy the output despite a live selection.
- s
- Swap Encode and Decode (outside text fields).
- t
- Cycle the color theme (outside text fields).
- ? or ⌘/Ctrl + /
- Open the shortcut help overlay.
- Esc
- Close the topmost dialog.