Skip to main content

How Base64URL Decoding Works

Base64URL decoding reverses a simple packing scheme: every 4 encoded characters carry 6 bits each, for 24 bits total, which split neatly into 3 bytes. The decoder looks up each character's 6-bit value in the RFC 4648 alphabet, concatenates the bits, then slices them into bytes and interprets the bytes as UTF-8 text.

Worked example: decoding "aGVsbG8" to "hello"
The string splits into the quartet aGVs and the triplet bG8. Looking up aGVs: a=26 (011010), G=6 (000110), V=21 (010101), s=44 (101100). Concatenated: 011010 000110 010101 101100, regrouped into bytes: 01101000, 01100101, 01101100, which are 104, 101, 108 in decimal, the ASCII codes for "hel". The remaining bG8 gives b=27 (011011), G=6 (000110), 8=60 (111100): 18 bits regrouped as 01101100 and 01101111, which are 108 and 111, the codes for "lo". Together: "hello".

When the input length is not a multiple of 4, the final group is shorter: 2 characters decode to 1 byte and 3 characters decode to 2 bytes. A length that leaves remainder 1 when divided by 4 (5, 9, 13, ...) can never be valid, because 6 bits cannot hold a whole byte.

Base64URL vs Base64: Reference Tables

The two alphabets are identical except for the last two values and the padding convention. That tiny difference is what makes Base64URL safe inside URLs, query strings, filenames, and HTTP headers.

Base64URL alphabet (RFC 4648, section 5)
Characters Values Notes
A-Z 0-25 Uppercase letters, same as standard Base64
a-z 26-51 Lowercase letters, same as standard Base64
0-9 52-61 Digits, same as standard Base64
- 62 Replaces + from standard Base64; URL-safe
_ 63 Replaces / from standard Base64; filename-safe
= padding At most two, only at the very end; usually omitted
Base64URL size overhead (padding-free)
Input bytes Output characters Overhead
1 2 100%
2 3 50%
3 4 33%
4 6 50%
5 7 40%
6 8 33%

Common Decoding Errors and How to Fix Them

Most decoding failures come from mixing up the two alphabets or from truncated tokens. The table below maps each error message to its cause and fix.

Common Base64URL decoding errors and fixes
Symptom Cause Fix
"Invalid character + at position N" Input is standard Base64, not Base64URL Use a standard Base64 decoder, or convert + to - and / to _
"Invalid length" (5, 9, 13...) Length mod 4 equals 1; a character is missing or extra Re-copy the token; no padding can repair it
Garbled text output Decoded bytes are binary, not UTF-8 text Inspect the hex dump; the payload may be a signature or hash
Python binascii.Error: Invalid padding Padding was stripped (JWT style) Re-add padding: s + "=" * (-len(s) % 4)

Related Tools

Frequently Asked Questions

Do I need to add the missing "=" padding before decoding Base64URL?

No. This decoder accepts Base64URL with or without padding: aGVsbG8 and aGVsbG8= both decode to "hello". It strips whitespace, counts any trailing "=" (at most two are allowed, only at the very end), and reconstructs the rest from the data length. Many systems, including JWTs, deliberately omit padding, so requiring it would break real-world tokens.

What is the difference between Base64URL and standard Base64?

Base64URL is the URL- and filename-safe variant defined in RFC 4648 section 5. Standard Base64 uses "+" (value 62) and "/" (value 63); Base64URL replaces them with "-" and "_" so encoded data survives URLs, query parameters, and filenames. Padding "=" is also usually omitted. Decoding "aGVsbG8+" with a standard decoder gives a different byte stream than decoding the same shape as Base64URL, so using the wrong alphabet silently corrupts data.

Why does the tool reject "+" and "/" instead of decoding them?

Because silently accepting them would lie about what you pasted. "+" and "/" never appear in valid Base64URL — they mean your string is standard Base64. The tool reports the exact 1-based position of the offending character and tells you plainly: that is standard Base64, not Base64URL. If you do have standard Base64, decode it with a standard Base64 decoder rather than forcing it through this one.

Can I decode a JWT with this tool?

Partially, by design. When the input has three dot-separated non-empty segments, the tool flags it as JWT-shaped and shows each segment with its length instead of decoding the whole token at once. Header and payload segments are plain JSON you can decode one at a time using the single-input box; the signature segment is raw HMAC or signature bytes, not text. Decoding a JWT never proves it is genuine — only signature verification with the correct key does, and that must happen on your server.

What happens if the decoded bytes are not valid UTF-8?

The tool still shows you the raw bytes. It validates the byte stream with a strict UTF-8 decoder; when validation fails — for example "__8" which decodes to the bytes FF FF — it displays a hex dump with per-byte decimal values and positions instead of guessing at a string. That way binary payloads like signatures or hashes are inspectable rather than silently mangled.

Why does the tool reject inputs whose length is 5, 9, or 13 characters?

Every 4 Base64URL characters encode exactly 3 bytes, so valid lengths can never leave a remainder of 1 when divided by 4. A length of 5, 9, 13, and so on always means a character is missing or extra — no padding scheme can fix it. The tool reports the invalid length instead of producing garbage bytes.

Which direction does this tool convert? How do I encode text to Base64URL?

This tool converts one direction only: Base64URL back to text. The inverse operation — text to Base64URL — is the dedicated String to Base64URL tool, and the two-way generalist that encodes and decodes in both directions is the Base64 URL Encoder. Keeping each direction in its own tool avoids the two-way bloat that buries the decode-specific features here, like per-quartet math and JWT detection.

Is my Base64URL input sent anywhere when I use this decoder?

No. All decoding happens in JavaScript inside your browser — the page makes zero network requests for conversion, and nothing you type or paste leaves your device. That makes it safe to paste sensitive material like JWTs or API tokens, since decoding Base64URL reveals its contents but never transmits them.

How do I decode Base64URL in JavaScript?

The built-in atob() only understands standard Base64, so convert first: replace every "-" with "+" and every "_" with "/", then add "=" padding until the length is a multiple of 4. After atob(), decode the byte string as UTF-8 with new TextDecoder().decode() over a Uint8Array, because atob() alone mangles non-ASCII characters. Example: "aGVsbG8td29ybGQ" becomes "hello-world" after this conversion.

How do I decode Base64URL in Python?

Use base64.urlsafe_b64decode(), but add the missing padding first since Python requires it: s + "=" * (-len(s) % 4). Then decode the resulting bytes as UTF-8. Example: base64.urlsafe_b64decode("aGVsbG8") returns b"hello". For encoding, base64.urlsafe_b64encode(data).decode().rstrip("=") produces the padding-free form that JWTs use.

Which characters are valid in Base64URL?

Exactly 64 data characters: A-Z (values 0-25), a-z (26-51), 0-9 (52-61), "-" (62), and "_" (63), plus optional trailing "=" padding. That is the entire alphabet defined in RFC 4648 section 5. Anything else, including "+" and "/" from standard Base64, whitespace inside the data, or more than two "=" signs, makes the input invalid.

Why is Base64URL used in JWTs instead of standard Base64?

A JWT travels inside HTTP headers, URLs, and query parameters, where "+" would be read as a space and "/" would be read as a path separator. Base64URL replaces those two characters with "-" and "_", which survive URLs untouched, and drops the "=" padding that would need percent-encoding. The header and payload segments of a JWT are Base64URL-encoded JSON; the signature segment is Base64URL-encoded raw bytes.

How much larger is Base64URL-encoded data than the original?

Base64URL expands data by a factor of 4/3, about 33 percent, because every 3 input bytes become 4 output characters. One byte encodes to 2 characters, two bytes to 3, three bytes to 4, four bytes to 6, five bytes to 7, and six bytes to 8. Padding-free Base64URL (the JWT style) never adds extra characters beyond that ratio.

How do I convert standard Base64 to Base64URL?

Replace every "+" with "-", every "/" with "_", and strip all trailing "=" characters. Example: standard Base64 "a+b/c==" becomes Base64URL "a-b_c". Going the other direction, restore "-" to "+", "_" to "/", then re-add padding so the length is a multiple of 4 before feeding it to a standard Base64 decoder.

Is Base64URL a form of encryption?

No. Base64URL is an encoding, not encryption: anyone can reverse it instantly with no key, which is exactly why JWT payloads are readable by design. Encoding only changes the representation so binary data survives text-based transport. If the content must stay secret, encrypt it first (for example with AES-GCM) and only then Base64URL-encode the ciphertext.

Can Base64URL encode binary data like images or files?

Yes. Base64URL encodes arbitrary bytes, not just text, which is why JWT signatures and API tokens use it for raw HMAC output. The decoded bytes are shown as text only when they form valid UTF-8; otherwise this tool displays a hex dump. One practical limit: very large files make extremely long strings, and URLs and headers have size limits, so Base64URL suits small payloads like tokens rather than multi-megabyte files.

Free tool by NRTechStudio