Photo by Towfiqu barbhuiya on Unsplash

Rails 7 breaks old signed messages

Jorge Rodriguez
Get on Board Dev
Published in
2 min readJun 28, 2023

--

If you find yourself migrating to rails 7.x and using its defaults, it is very likely your persisted signed messages (used mostly in URLs) will stop working.

Signed messages come from using ActiveSupport::MessageVerifier for scenarios like remember-me tokens or auto-unsubscribe links where there is no session available.

ActionText or Trix editor use it too to create permanent signed links to the uploaded attachments (through ActiveStorage).

# config/application.rb
#
module Getonboard
class Application < Rails::Application
# Use the default settings of Rails 7
config.load_defaults 7.0
...
end
end

Our case wasn’t different, we use Trix editor and a lot of remember-me tokens or subscribe/unsubscribe links across our codebase, also secrets encrypted to allow our users to access their private data thru using our API.

The problem is not well documented, and we had to dig deeper to diagnose it and come up with a solution. The issue had to do with Rails 7 changing the key generation for signing messages from using SHA1 to using SHA256, so your old permanent signatures were encrypted with SHA1 and now Rails is trying to decrypt them by using a SHA256 digest generated key.

The good news is that buried in the ActiveSupport::MessageVerifier API documentation is the support to add rotations keys as fallbacks in case the message verifier fails using the original — claps to the developers for the clever decision to do that.

Our solution consisted in adding rotation keys for all the message verifiers used across the codebase — you can accommodate this code for your personal case too.

# config/initializers/message_verifiers_rotates.rb
#
Rails
.application
.config
.after_initialize do |app|
# Create an old SHA1 key generator
sha1_key_generator =
ActiveSupport::KeyGenerator.new(app.secret_key_base,
iterations: 1000,
hash_digest_class: OpenSSL::Digest::SHA1)

# Create rotates for all the currently used veririfier
# In theory all the verifiers but ActiveStorage can be
# removed from the list in a few months from now on.

# Note: ActiveStorage is used by trix to create permanent signed ids
# for the attached images of the blog posts.
#
verifiers = [
"ActiveStorage",
...
]

verifiers.each do |verifier|
app
.message_verifier(verifier)
.rotate(sha1_key_generator.generate_key(verifier))
end
end

--

--

Jorge Rodriguez
Get on Board Dev

1. Software Engineer @fleetio.com 2. Co-Founder @getonbrd (500 SF)