Random base64 generator
Random values in the RFC 4648 base64 and base64url alphabets, with padding as an option and the bit count shown.
This page generates, it does not encode
If you arrived here wanting to turn text you already have into base64, this is the wrong tool. There is no input field for your data, and there will not be one. This site generates random values; it does not transform values you supply.
The distinction matters more than it sounds. An encoder takes something you already have and rewrites it in a different alphabet, which changes nothing about how guessable it is. A generator produces something that did not exist before, drawn from a cryptographic source. Base64 of the word password is still the word password.
What this page does is draw random bytes and render them in the base64 or base64url alphabet, which is what you want when a system asks for a base64 secret, a base64url token, or a value that has to survive a URL.
Two alphabets, one encoding
RFC 4648 defines both. Section 4 is the standard alphabet and section 5 is the URL and filename safe one. The first 62 symbols are identical in both: A to Z, then a to z, then 0 to 9. Only the last two differ. Standard base64 uses + at index 62 and / at index 63; base64url uses - and _ in the same positions.
That two-character difference exists for one reason, and it is worth stating precisely. In application/x-www-form-urlencoded content, + decodes to a space. A token containing a + placed unencoded in a query string or a form body silently arrives as a different string, and the failure looks like an authentication bug rather than an encoding bug. The / has a milder version of the same problem in path segments and filenames.
Because the alphabets overlap on 62 of 64 symbols, a base64 value can look perfectly URL-safe for a long time and then break. Roughly one character in 32 is a + or a /, so a 43-character token hits one about three quarters of the time, and a 22-character one about half the time. That is often enough to reach production and rare enough not to be caught in testing.
| Indices 0-61 | Index 62 | Index 63 | Padding | |
|---|---|---|---|---|
| Section 4, standard | A-Z a-z 0-9 | + | / | = required |
| Section 5, URL and filename safe | A-Z a-z 0-9 | - | _ | = usually omitted |
Padding, and the 4/3 expansion
Base64 works in groups of three bytes. Twenty-four bits divide evenly into four 6-bit characters, so three bytes always becomes four characters and the expansion is exactly 4/3, a 33% overhead. Hex, by comparison, is 2 characters per byte, a 100% overhead.
When the input is not a multiple of three, the last group is short. One leftover byte becomes two characters plus two = signs; two leftover bytes become three characters plus one =. The padding exists so that a decoder reading a concatenated stream knows where one value ends. RFC 4648 section 3.2 allows it to be omitted where the length is known by other means, and section 5 usage almost always omits it, because = is itself awkward in a URL.
For 32 bytes: ten full groups cover 30 bytes and produce 40 characters, and the two remaining bytes produce three more. That is 43 characters unpadded, or 44 with a single = on the end.
| Bytes | Bits | Unpadded characters | Padded |
|---|---|---|---|
| 12 | 96 | 16 | 16, no padding needed |
| 16 | 128 | 22 | 24, two = signs |
| 24 | 192 | 32 | 32, no padding needed |
| 32 | 256 | 43 | 44, one = sign |
| 48 | 384 | 64 | 64, no padding needed |
| 64 | 512 | 86 | 88, two = signs |
Why 43 characters carries 256 bits and not 258
Forty-three base64 characters occupy 43 times 6, which is 258 bit positions. Thirty-two bytes is 256 bits. Two bit positions therefore have nothing to encode, and the encoder sets them to zero. Those two spare bits live in the final character, which means the last character of the base64 of any 32-byte value is drawn from only 16 of the 64 symbols: 0, 4, 8, A, E, I, M, Q, U, Y, c, g, k, o, s, w. We confirmed this over 20,000 samples per size.
The 16-byte case is the same effect, larger. Twenty-two characters is 132 bit positions against 128 bits of value, so four bits are forced and the last character is always one of exactly four symbols: A, Q, g or w.
This cuts both ways, and the second direction is the one that causes bugs. A value built by drawing 43 uniformly random characters from the base64url alphabet carries 258 bits, not 256 - but it is not the encoding of any byte string. The spare bits are not zero, so it is a non-canonical base64 value, and a strict decoder is entitled to reject it. Some do. If a token has to round-trip through base64 decoding anywhere in your stack, generate bytes and encode them; do not generate characters.
Generate bytes, then encode. A token assembled character by character from the base64 alphabet is not decodable base64, and no competitor page mentions this.
Which form to ask for
Use base64url without padding for anything that goes in a URL, a path segment, a filename, a cookie value or a JWT. The JWS and JWT specifications require exactly this form, which is why every JWT segment ends without an = sign.
Use standard base64 with padding when a specification or a library asks for base64 without qualification, which usually means MIME, HTTP Basic authentication, a PEM body, or a data URI. If you are handing the value to something you did not write, padded standard is the safer default.
For a secret, 32 bytes is the size to reach for. It gives 256 bits, renders as 43 base64url characters, and is the width that matches an HMAC-SHA-256 key and an AES-256 key. Sixteen bytes at 22 characters and 128 bits is enough for a session token and is the smaller, tidier choice where length shows in a URL.
Doing this in your own code
JavaScript (browser and Node 19+)
// 32 random bytes -> 43 unpadded base64url characters, carrying 256 bits.
function randomBase64Url(bytes) {
const b = crypto.getRandomValues(new Uint8Array(bytes));
const std = btoa(String.fromCharCode(...b));
return std.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}
randomBase64Url(32); // 43 characters
randomBase64Url(16); // 22 characters
// Node 16+ has the alphabet built in:
// require("node:crypto").randomBytes(32).toString("base64url") The spread into String.fromCharCode is fine for small inputs and will overflow the call stack on large ones. Loop for anything sizeable.
Python 3.6+
import base64, secrets
secrets.token_urlsafe(32) # 43 characters, RFC 4648 section 5, unpadded
# The standard alphabet, if you genuinely need + and /:
base64.b64encode(secrets.token_bytes(32)).decode() # 44 chars, one "="
base64.urlsafe_b64encode(secrets.token_bytes(32)) # padded, - and _ token_urlsafe takes a byte count. token_urlsafe(32) returns 43 characters, not 32.
Go
import (
"crypto/rand"
"encoding/base64"
)
b := make([]byte, 32)
if _, err := rand.Read(b); err != nil {
panic(err)
}
base64.RawURLEncoding.EncodeToString(b) // 43 chars, - and _, unpadded
base64.URLEncoding.EncodeToString(b) // 44 chars, - and _, padded
base64.StdEncoding.EncodeToString(b) // 44 chars, + and /, padded The four encodings differ only in alphabet and padding. Raw means unpadded.
Rust
// base64 = "0.22", getrandom = "0.3"
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
let mut b = [0u8; 32];
getrandom::fill(&mut b).expect("entropy source unavailable");
let token = URL_SAFE_NO_PAD.encode(b); // 43 characters PHP 7+
$raw = random_bytes(32);
// Standard, RFC 4648 section 4:
base64_encode($raw); // 44 characters
// URL safe and unpadded, RFC 4648 section 5:
rtrim(strtr(base64_encode($raw), "+/", "-_"), "="); // 43 characters Shell
# Standard alphabet, padded. 32 bytes -> 44 characters.
openssl rand -base64 32
# base64url, unpadded. 43 characters.
openssl rand -base64 32 | tr '+/' '-_' | tr -d '='
# coreutils 8.31+ knows the alphabet by name:
openssl rand 32 | basenc --base64url | tr -d '=' openssl rand -base64 wraps long output at 64 columns. Pipe through tr -d "\n" if you are capturing more than 48 bytes.
Questions
Can I paste my own text in and base64 encode it here?
No. This is a generator, not an encoder, and that is a deliberate scope decision for the whole site. Encoding your text would also not make it secret: base64 is a rewriting, not a cipher, and anyone can reverse it.
What is the difference between base64 and base64url?
Only the last two symbols and the padding convention. Both use A-Z, a-z and 0-9 for indices 0 to 61. Standard base64, from RFC 4648 section 4, uses + and / for 62 and 63. base64url, from section 5, uses - and _ instead, and usually drops the = padding. The reason is that + decodes to a space in form-encoded content.
Why is 32 bytes 43 characters and not 42 or 44?
Base64 encodes three bytes as four characters. Thirty bytes give 40 characters, and the two remaining bytes give three more, so 43 unpadded. Padding to a multiple of four adds one = for 44 characters total.
Is it safe to strip the padding?
Yes, when the receiver knows the length or accepts unpadded input, which is the normal case for tokens and is what JWT requires. RFC 4648 section 3.2 permits it explicitly. Do not strip padding from a value going into a general-purpose decoder that has not been told to expect it.
How many bits is a 22-character base64 token?
It depends how it was made, and this is the subtlety. If it is the encoding of 16 random bytes, it carries 128 bits and its last character is always A, Q, g or w. If it is 22 characters drawn uniformly from the 64-symbol alphabet, it carries exactly 132 bits but is not valid canonical base64.
Does base64 make a value more secure?
No. Encoding changes the alphabet, not the entropy. The security comes entirely from how many random bytes went in.