base64.urlsafe_b64encode / urlsafe_b64decode
The base64url alphabet of RFC 4648: - replaces + and _ replaces /. Python keeps the = padding on encode and requires it on decode — JWTs and most URL tokens strip it.
Demo
import base64 data = '???>>>'.encode() (base64.b64encode(data), base64.urlsafe_b64encode(data))
JWTs use base64url with the padding removed, so a payload whose length is not a multiple of 4 raises Incorrect padding until you add -len(s) % 4 = signs back. The decoder translates - and _ to + and / and then runs the normal lenient decoder, which is why standard input such as "+/+/" decodes too. In the non-ASCII payload, "Wm_D" is where the URL-safe _ stands in for the / of standard Base64.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| s | bytes-like (encode) · bytes-like | ASCII str (decode) | yes | The data to encode, or the URL-safe Base64 text to decode. The decoder also accepts + and /. |
Return value
bytes — Encode: URL-safe Base64 as ASCII bytes, = padding kept. Decode: the original bytes.
Common patterns
import base64, secrets token = base64.urlsafe_b64encode(secrets.token_bytes(16)).rstrip(b'=').decode('ascii')
import base64, json payload = token.split('.')[1] claims = json.loads(base64.urlsafe_b64decode(payload + '=' * (-len(payload) % 4)))
import base64 def b64url_encode(b): return base64.urlsafe_b64encode(b).rstrip(b'=').decode('ascii') def b64url_decode(s): return base64.urlsafe_b64decode(s + '=' * (-len(s) % 4))
Examples
Pitfalls
import base64 base64.urlsafe_b64decode('eyJzdWIiOiIxMjMifQ')
import base64 s = 'eyJzdWIiOiIxMjMifQ' base64.urlsafe_b64decode(s + '=' * (-len(s) % 4))
import base64 base64.b64decode('-_-_')
import base64 base64.urlsafe_b64decode('-_-_')
import base64 f"/files/{base64.urlsafe_b64encode(b'id-7')}"
import base64 f"/files/{base64.urlsafe_b64encode(b'id-7').decode()}"
When to use
- Tokens in URLs and query strings, file names, cookie values
- JWT / JOSE (base64url, padding stripped)
- APIs that specify plain Base64 → b64encode
- Verifying JWTs — decoding is not validating; use a JWT library
Notes
FAQ
Take the middle part (token.split('.')[1]), add '=' * (-len(part) % 4), call base64.urlsafe_b64decode and json.loads the result. That only reads the claims — it does not check the signature.