Three Base64 Methods in Ruby — Which to Use When
Ruby's standard library ships three Base64 encoders, and picking the wrong one is the #1 cause of confused-looking output. Here's the mental model:
Base64.encode64(data)— MIME format. Inserts a newline every 60 characters and appends a trailing newline. Designed for email bodies (RFC 2045). Use only when you're building a MIME message manually.Base64.strict_encode64(data)— Same Base64 alphabet, no newlines. One continuous string. This is what you almost always want: safe for JSON, HTTP headers, database columns, and env vars.Base64.urlsafe_encode64(data, padding: true|false)— URL-safe alphabet (-and_instead of+and/). Use for URL query strings, filenames, and JWT tokens. Ruby 2.5+ accepts thepadding:keyword to omit trailing=.
Encoding a String — The Standard Pattern
require 'base64'
text = 'Hello 世界 👋'
# Standard (single-line output)
encoded = Base64.strict_encode64(text)
puts encoded
# => "SGVsbG8g5LiW55WMIPCfkYs="
# MIME-formatted (with newlines) — usually NOT what you want
mime_encoded = Base64.encode64(text)
puts mime_encoded
# => "SGVsbG8g5LiW55WMIPCfkYs=\n"
# Note the trailing newline. Also inserts \n every 60 chars for longer inputs.
# URL-safe (for query strings and filenames)
urlsafe = Base64.urlsafe_encode64(text)
puts urlsafe
# => "SGVsbG8g5LiW55WMIPCfkYs="
# JWT-style (URL-safe + no padding, Ruby 2.5+)
jwt = Base64.urlsafe_encode64(text, padding: false)
puts jwt
# => "SGVsbG8g5LiW55WMIPCfkYs"Encoding a File
require 'base64'
# Small to medium files — read all at once
# File.binread reads in binary mode (important on Windows to avoid CRLF translation)
encoded = Base64.strict_encode64(File.binread('./image.png'))
puts encoded.length # roughly 4/3 the file size
# Alternative — block form (explicit close)
encoded = File.open('./image.png', 'rb') do |f|
Base64.strict_encode64(f.read)
end
# Data URL for embedding in HTML
def image_data_url(path, mime_type: 'image/png')
b64 = Base64.strict_encode64(File.binread(path))
"data:#{mime_type};base64,#{b64}"
end
# Large files — stream so we don't load everything into memory at once
def encode_large_file_streaming(input_path, output_path)
File.open(output_path, 'w') do |out|
File.open(input_path, 'rb') do |input|
# Read 57 bytes at a time — encodes to exactly 76 Base64 chars (MIME line width)
# 57 is chosen because 57*4/3 = 76, so each chunk is one clean line
until input.eof?
chunk = input.read(57 * 1024) # 57 KB blocks
out.write(Base64.strict_encode64(chunk))
end
end
end
endURL-Safe Base64 and JWT-Style Encoding
require 'base64'
require 'json'
payload = { user_id: 42, role: 'admin' }.to_json
# Standard Base64 (uses + and /)
std = Base64.strict_encode64(payload)
puts std
# => "eyJ1c2VyX2lkIjo0Miwicm9sZSI6ImFkbWluIn0="
# URL-safe Base64 (uses - and _)
urlsafe = Base64.urlsafe_encode64(payload)
puts urlsafe
# => "eyJ1c2VyX2lkIjo0Miwicm9sZSI6ImFkbWluIn0="
# JWT-style: URL-safe + no padding
jwt = Base64.urlsafe_encode64(payload, padding: false)
puts jwt
# => "eyJ1c2VyX2lkIjo0Miwicm9sZSI6ImFkbWluIn0"
# Decoding back
decoded = Base64.urlsafe_decode64(jwt)
puts JSON.parse(decoded).inspect
# => {"user_id"=>42, "role"=>"admin"}
# Manual DIY JWT header + payload encoding
def b64url(bytes)
Base64.urlsafe_encode64(bytes, padding: false)
end
header = b64url({ alg: 'HS256', typ: 'JWT' }.to_json)
payload_encoded = b64url({ sub: 'alice', exp: Time.now.to_i + 3600 }.to_json)
signing_input = "#{header}.#{payload_encoded}"Encoding a Hash / JSON Object
require 'base64'
require 'json'
data = {
user_id: 42,
email: '[email protected]',
roles: ['admin', 'editor'],
joined: '2026-01-15'
}
# Serialize → Base64
encoded = Base64.strict_encode64(data.to_json)
puts encoded
# Round trip
decoded_hash = JSON.parse(Base64.strict_decode64(encoded), symbolize_names: true)
puts decoded_hash == data # true
# Rails-idiomatic version using ActiveSupport
# encoded = ActiveSupport::Base64.encode64s(data.to_json) # DEPRECATED
# In modern Rails just use the standard library — Base64.strict_encode64.Building an HTTP Basic Auth Header in Ruby
require 'base64'
require 'net/http'
require 'uri'
def basic_auth_header(user, password)
token = Base64.strict_encode64("#{user}:#{password}")
{ 'Authorization' => "Basic #{token}" }
end
# Use it
uri = URI('https://api.example.com/protected')
req = Net::HTTP::Get.new(uri)
basic_auth_header('admin', 'secret123').each { |k, v| req[k] = v }
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(req)
end
# Simpler alternative — Net::HTTP has basic_auth built in
req.basic_auth('admin', 'secret123') # does the encoding for youCommon Pitfalls in Ruby Base64 Code
- Using
Base64.encode64when you want a single line — encode64 adds a newline every 60 characters plus a trailing newline. That breaks JSON, HTTP headers, and env vars. Default tostrict_encode64. - Forgetting
require 'base64'in Rails 7+ — After Base64 was extracted from Ruby core into a standalone gem in Ruby 3.4, Rails no longer autoloads it. Add the require explicitly or you getNameError: uninitialized constant Base64. - Reading files without binary mode —
File.read(path)on Windows translates\r\n→\nand corrupts binary files. Always useFile.binreador open with mode"rb". - Chaining
.delete("=")instead of usingpadding: false— Both work, buturlsafe_encode64(data, padding: false)is idiomatic and avoids a second string traversal. - Assuming decode64 handles URL-safe input —
Base64.decode64uses the standard alphabet only. If the input has-or_, useurlsafe_decode64or you get garbled output.
Command Line Alternative
For quick one-offs, use IRB (Ruby REPL) or a one-liner via the shell:
# Ruby one-liner from the shell
ruby -rbase64 -e 'puts Base64.strict_encode64("Hello")'
# => SGVsbG8=
# Encode a file from the CLI
ruby -rbase64 -e 'puts Base64.strict_encode64(File.binread(ARGV[0]))' image.png
# Standard base64 CLI (usually installed alongside Ruby on macOS/Linux)
echo -n "Hello" | base64
# => SGVsbG8=Key Facts
- Library:
- base64 (standard library — must be required explicitly in Ruby 3.4+)
- Modern encoder:
- Base64.strict_encode64(data) — single-line output
- MIME encoder:
- Base64.encode64(data) — inserts newlines every 60 chars
- URL-safe encoder:
- Base64.urlsafe_encode64(data, padding: false)
- Input type:
- String (Ruby strings can hold arbitrary bytes — use File.binread for files)
- Output type:
- String — ready to drop into JSON, headers, env vars
- Rails 7+ note:
- Requires require 'base64' explicitly — no longer autoloaded
Related Base64 Tools
- Base64 Encode Online — general-purpose browser encoder
- Base64 Encode in Python — Python 3 equivalent
- Base64 Encode in JavaScript — Node.js and browser
- Base64 Encode in PHP — PHP base64_encode
- URL-Safe Base64 — cross-language URL encoding guide
- Base64 Decode Online — reverse the encoding
- JWT Debugger — inspect JWT tokens