How to decode Base32
- Paste the string into Input · Base32 (RFC 4648). Upper or lower case, spaces between groups and line breaks are all accepted, and the
=padding is optional. - Read the decoded text in Output · Text. The default charset is UTF-8; change Charset under the output if the text came from another system.
- If the output is a jumble of symbols, the data is binary. Set To to Hex or Base64 to see the bytes, or click Save bytes to download them as a file.
- If the input uses another alphabet, change From to Base32hex, Crockford Base32 or z-base-32.
- To encode, click Text → Base32 (RFC 4648) in the direction toggle, or use the Base32 encoder.
What the decoder accepts and rejects
The decoder is lenient about formatting and strict about content:
| Input | Result |
|---|---|
JBSWY3DP | Hello |
jbswy3dp | Hello; case does not matter |
JBSW Y3DP EHPK 3PXP | 10 bytes, 48656c6c6f21deadbeef in hex |
MZXW6YQ | foob; missing padding is fine |
JBSWY3D0 | Error: unexpected character "0" at position 8 |
The error points at the first character that is not in the alphabet. A 0, 1, 8 or 9 almost always means the string uses a different Base32 alphabet, and a + or / means it is really Base64; try the Base64 decoder.
Decoding a 2FA or TOTP secret
The key an authenticator app shows during setup, often grouped as jbsw y3dp ehpk 3pxp, is RFC 4648 Base32. Decoding it gives the raw HMAC key, which is random bytes, so look at it as Hex rather than Text. The length tells you the key size: 16 characters are 10 bytes, 32 characters are 20 bytes (160 bits, the size RFC 4226 recommends), 52 characters are 32 bytes.
To check that you have the right secret, generate a code from it. This Python function decodes the secret the same lenient way, then follows RFC 6238:
import base64, hashlib, hmac, struct
def totp(secret, t, digits=6, step=30):
s = secret.replace(" ", "").upper()
key = base64.b32decode(s + "=" * (-len(s) % 8))
mac = hmac.new(key, struct.pack(">Q", t // step), hashlib.sha1).digest()
off = mac[-1] & 0x0F
code = struct.unpack(">I", mac[off:off + 4])[0] & 0x7FFFFFFF
return str(code % 10**digits).zfill(digits)
totp("GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ", 59, 8) # '94287082'
The secret and the expected 94287082 are the SHA-1 test vector from RFC 6238. For the current code, pass int(time.time()) as t. More decoding patterns are on the Python page.
IPFS CIDv1 and other prefixed Base32
Some formats put a marker in front of the Base32. IPFS CIDv1 strings start with b, the multibase code for lower-case RFC 4648 Base32 without padding: in bafybei… the b is the prefix and afybei… is the data. Remove the b, decode, and set To to Hex. The first bytes are the CID version (01), the content type (70 for dag-pb) and the multihash header (1220 for a 32-byte SHA-256).
Tor v3 onion addresses work the same way without a prefix: the 56 characters before .onion are Base32 of 35 bytes, a 32-byte public key, a 2-byte checksum and a version byte (03).
Common problems
- Python raises
binascii.Error: Non-base32 digit found. The input is lower case. Passcasefold=Truetob32decode, or call.upper()first. - Python raises
binascii.Error: Incorrect padding. The=signs were stripped. Pad the length to a multiple of 8, as in the function above. base32 -dsaysinvalid input. GNU coreutils accepts neither lower case nor spaces. Clean the string first or decode it here.- The text decodes, but to the wrong thing. Base32hex and Crockford strings decode without an error under the wrong alphabet. If the source says “Base32” but the string has no
0,1,8or9, RFC 4648 is still the best guess; otherwise try the other two.
FAQ
How do I decode a TOTP secret?
Paste the secret (the secret= value of an otpauth:// link, or the text key an app shows instead of the QR code) and set To to Hex. The result is the raw HMAC key. It is random bytes, so the Text output will look like garbage, and that is expected.
Why does Python say Incorrect padding when decoding Base32?
base64.b32decode wants the length to be a multiple of 8. Add the missing = first: s + "=" * (-len(s) % 8). This decoder does not need padding.
Can I decode a ULID here?
Not directly. A ULID uses the Crockford alphabet, but it encodes one 128-bit number in 26 characters, starting with 2 spare bits. The Crockford option here bit-packs bytes from the first character, so it returns shifted bytes for a ULID.
Which characters are invalid in Base32?
In RFC 4648 Base32, anything other than A–Z, 2–7 and trailing =. The digits 0, 1, 8 and 9 are the usual sign that the string is base32hex or Crockford; switch From to try them.