Generate a Rails Secret Key Base — Free secret_key_base Generator
Click Generate and the Rails Secret Key Base Generator hands you a fresh secret_key_base — a 128-character hex string, formatted exactly like the output of the rails secret command — ready to drop into your Rails application's config. Your browser's built-in cryptographically secure random number generator produces the value locally, so it never touches a server on its way to you.
Every application handling user auth depends on one foundational value: secret_key_base. Using this rails secret key base generator gives you a cryptographically secure, randomly generated string that protects your users from cookie tampering, session hijacking, and unauthorized access — the kind of vulnerability that can compromise an entire web application overnight. Whether you are deploying to a live host for the first time or rotating an exposed key, understanding how secret_key_base works empowers you to make the right decisions with confidence.
What Is secret_key_base and How Does the Rails Secret Key Base Generator Work?
The Role of the Secret-Key in Your Application
secret_key_base is the input secret to your framework's internal key derivation system. It is not used directly to cipher or sign data — instead, it seeds the key_generator (an instance of ActiveSupport::CachingKeyGenerator wrapping ActiveSupport::KeyGenerator) which derives purpose-specific sub-keys using PBKDF2 with a default of iterations 1000. Those derived keys power every ActiveSupport::MessageVerifier and ActiveSupport::MessageEncryptor — the message encryptor — instance in your app, covering signing session data, protecting user data, authenticated encrypted cookie jars, and all signed messages throughout the stack. Token generation relies on this same derivation chain for CSRF and remember-me tokens.
"Your secret key is used for verifying the integrity of signed cookies. If you change this key, all old signed cookies will become invalid."
Think of secret_key_base as similar to a random value used in hashing — a nonce that makes brute-force attacks computationally infeasible. Without a strong, private value here, an attacker who knows your key could forge any session token your app relies on for authentication, bypass session protection entirely, and gain unauthorized access to protected resources. This makes it one of the highest-sensitivity values in your entire codebase — treat it like a private key or database password.
How the Framework Uses the Key Generator Internally
When the app boots, it sets two critical entries in the middleware env hash: action_dispatch.secret_key_base (the raw value) and action_dispatch.key_generator (the memoized ActiveSupport::CachingKeyGenerator instance). Every cookie jar that signs or ciphers data calls into this shared key generator instance to derive a per-purpose key using a verifier name and an optional random modifier.
The flow looks like this at runtime:
- The app reads secret_key_base from its configured source (ENV, stored config values, or the tmp directory fallback).
- It builds an
ActiveSupport::KeyGeneratorseeded with that value, then wraps it in aActiveSupport::CachingKeyGeneratorto avoid repeating expensive PBKDF2 derivations. This component acts as a key generator for all downstream operations. - The message verifier for each cookie purpose (signed cookie modifier, protected cookie modifier, authenticated encrypted cookie modifier) derives its own sub-key. This is where hashing with PBKDF2 occurs internally.
ActiveSupport::MessageVerifieruses that sub-key to generate and verify signed messages, preventing tampered data from being accepted.- The message encryptor (
ActiveSupport::MessageEncryptor) uses it for protecting cookie values, ensuring secure data is never readable client-side. This encrypts secrets stored in session cookies.
This is why data integrity, cookie protection, and session integrity all flow from a single source: the quality and secrecy of your secret_key_base. Understanding this cascade is essential knowledge for any backend developer working with the framework's protection layer.
Where secret_key_base Lives in the Rails::Application Class
secret_key_base is an instance public method defined on Rails::Application, which itself inherits from Rails::Engine and ultimately from Rails::Railtie. This class hierarchy means every app instance is simultaneously an Engine, so all railties and engines participate in the same startup sequence that loads your key.
The class also exposes several related methods worth knowing:
- create(initial_variable_values = {}, &block)
- Class method that initializes the application singleton and yields to a setup block. This is called once during the startup sequence.
- inherited(base)
- Class method hook that fires when your application class inherits from
Rails::Application, registering it as the global app instance. - instance()
- Returns the singleton application instance. Calling
initialized?()on this instance tells you whether the full startup sequence has completed — useful for runtime diagnostics. - find_root(from)
- Resolves the application's root directory, important in multi-engine setups where different engines may maintain separate setup trees. This is especially relevant in large apps built on top of
Rails::Engine. - eager_load!
- Forces the framework to load all application code immediately, which is triggered in live deployments. The secret_key_base must be available before this runs, since cipher instances are initialized as part of eager loading.
The framework's protection documentation (available at guides.rubyonrails.org/security.html#custom-credentials) provides complementary documentation on how this value ties into the broader application protection model. Knowledge of this class structure is valuable for any developer building on the platform, the open-source web framework written in the Ruby language.
Generating and Configuring Your Rails secret_key_base
How to Generate Rails secret_key_base Using the CLI Command
The canonical way to generate a key is the built-in CLI command. The framework delegates to the language runtime's SecureRandom library — specifically the SecureRandom library's hex method — which reads from /dev/random on Unix systems (or the OS CSPRNG equivalent) to produce a randomly generated string of cryptographically strong bytes. This ensures genuine randomness in your secret generation, making it suitable as a cryptographic key. This is the recommended approach to generate key material for production use, and using the rails secret key base generator built into the CLI is the fastest path to a compliant value.
# Generate a new secret_key_base using the CLI — this is how you generate rails secret_key_base
rails secret
# Example output (a random hex string of 128 hex characters = 64 bytes):
# 3b8d4f9a2c1e7b6f0a5d8e2c9f4b1a7e3d6c0f9b2e5a8d1c4f7b0e3a6d9c2f5b8e1a4d7c0f3b6e9a2d5c8f1b4e7a0d3If you do not have the runtime installed — for example, on an Ubuntu 16.04 host configured to run only container workloads — you face a classic chicken and egg problem: you need the key before you build the container artifact, but the artifact contains the runtime. Fortunately, if you have OpenSSL available (as most Linux base images do, including those with Perl installed), you can generate secret key material using a system command that produces an equivalent random hex string:
# Generate a 64-byte random hex string without the runtime installed
# Requires the SSL library on the base VM or host
openssl rand -hex 64
# Equivalent to SecureRandom.hex(64)
# Produces a 128-character hex string suitable for use as secret_key_baseThis approach is commonly used in container build steps and CI pipelines where the runtime is not yet available. The output is a hex string of sufficient entropy for use as a live cryptographic key. Whether you use rails secret, rake secret (older syntax), or the system SSL command, the resulting value is functionally equivalent — a random value of 64 bytes expressed as a 128-character hex string, with url_safe characteristics for config value storage.
Today I learned (a common piece of knowledge sharing in the web framework community) that rake secret and rails secret produce the same output — rake secret is the older form. Both remain valid today, though rails secret is preferred in modern versions. This is valuable learning for teams migrating from older setups.
Setting the Key via Config Value vs. Stored Credentials
The framework resolves secret_key_base through a priority chain at startup. Understanding this order prevents misconfiguration in your live context:
- ENV["SECRET_KEY_BASE"] — highest priority; if this config value is set, the framework uses it immediately without checking stored keys.
- credentials.secret_key_base — reads from the encrypted config store, decrypted using
config/master.keyor theRAILS_MASTER_KEYenv value. - secrets.secret_key_base — legacy fallback via the old flat file; triggers a removal notice in version 7.1 and will be removed in a subsequent release.
- tmp/development_secret.txt or tmp/local_secret.txt — auto-generated fallback used only in local and test contexts; never present in live deployments.
For host-based deployments without encrypted config stores, set the value directly in your shell or deployment setup:
# Export SECRET_KEY_BASE as a config value for live deployment
# Replace the value below with the output of `rails secret` or the SSL command
export SECRET_KEY_BASE=3b8d4f9a2c1e7b6f0a5d8e2c9f4b1a7e3d6c0f9b2e5a8d1c4f7b0e3a6d9c2f5b8e1a4d7c0f3b6e9a2d5c8f1b4e7a0d3
# Verify the value is set in the active context
echo $SECRET_KEY_BASEIn containerized deployments, inject this as a runtime value in your Dockerfile (for build-time usage like precompile assets) or — better — via your orchestrator's secrets management system at runtime, so the value never appears in unencrypted files or container artifact layers. The built container artifact itself should not bake in the live secret; instead, the running container receives it at startup through an injected config value, following containerization best practices.
Reminder: Never commit your secret_key_base value to version control. Even in a private repository, committing protected values creates a permanent record in git history that is extremely difficult to fully erase. Use secret scanning tools and commit scanning to catch accidental key exposure before it reaches your remote — this is a core principle of developer protection and application integrity.
Using Encrypted Credentials to Store the Key Securely
The encrypted config store was introduced in version 5.2 as the recommended approach for sensitive value storage. In version 7.1, the older flat-file-based approach was phased out in favor of this encrypted method, completing the transition to an encrypted-by-default workflow. In the latest stable release (the 7.0 series and beyond), the stored config API is the correct way to keep your live secret_key_base safe.
The encrypted config file (config/credentials.yml.enc) encrypts secrets using AES-128-GCM with a key stored in config/master.key. The master key is itself a private key — never committed to version control — and can be provided at runtime via the rails_master_key config value. This is distinct from secret_key_base: the master key decrypts the stored config which contains secret_key_base; they are related but serve different roles. The encrypted file itself is safe to commit since it encrypts secrets at rest.
# Open the encrypted config store for editing
# The framework decrypts it using config/master.key and opens it in your $EDITOR
rails credentials:edit
# Inside the config store (YAML format, shown decrypted):
# secret_key_base: 3b8d4f9a2c1e7b6f0a5d8e2c9f4b1a7e3d6c0f9b2e5a8d1...
# Access the value at runtime (preferred approach — reads from active context):
Rails.application.secret_key_base
# Equivalent access path (still works but less recommended than the above):
Rails.application.credentials.secret_key_baseYou can also use custom config files per context in version 6 and later:
# Edit live-context-specific config store
rails credentials:edit --environment production
# This creates config/credentials/production.yml.enc
# Access in code via Rails.application.credentials (context-scoped automatically)The encrypted config approach satisfies stored key management best practices: the sensitive data is protected at rest, the enc file is version-controlled safely, and the decryption key is never stored alongside it. This pattern also supports Rails.application.credentials as the single authoritative access point, replacing the older path that now issues a removal notice.
How the Boot Process Loads secret_key_base
The startup sequence in an app is orchestrated by Rails::Application, which acts as the central coordinator for all railties and engines. Rails::Railtie provides the hook mechanism through which setup is applied. The sequence matters for understanding when your secret_key_base becomes available:
- config.before_configuration — fires before the main app setup file is evaluated. This is the earliest hook, useful for injecting ENV-based values.
- Rails::Application::Bootstrap initializers run next, setting up the logger, middleware stack, and core framework components.
- config/initializers/* files are loaded after the framework initializers, in alphabetical order. Any code referencing secret_key_base here will have access to the resolved value.
- before_initialize hooks from engine initializers fire between Bootstrap and the application initializers — keep this in mind for multi-engine apps.
- Finally, eager_load! runs in live contexts, loading all application code. The action_dispatch.key_generator entry in the middleware env is set before this point, so all verifier and encryptor instances are initialized with the correct key.
The main app setup file is the primary location for application-level setup. If you need to set secret_key_base programmatically (rare, but valid for testing scenarios), you can do so there:
# config/application.rb — example of programmatic setup (uncommon)
module MyApp
class Application < Rails::Application
# The framework will prefer ENV["SECRET_KEY_BASE"] over this value
# Only use this pattern in exceptional circumstances
config.secret_key_base = ENV.fetch("SECRET_KEY_BASE") { SecureRandom.hex(64) }
end
endThe config_before_initialize pattern and Railtie#initializer hooks give you fine-grained control over this loading order, which is particularly important when building engines or mountable apps that depend on the parent application's secret_key_base.
Using secret_key_base_dummy for Asset Precompilation
One common challenge in container-based deployments is the assets precompile step during the image build phase. The framework requires a secret_key_base to boot, but you should not embed your real live key values into a container artifact layer — this creates a key exposure risk that persists in the artifact history.
The framework solves this with the secret_key_base_dummy mechanism. Setting SECRET_KEY_BASE_DUMMY=1 in your build context tells the framework to generate a temporary placeholder without requiring your real live key to be present:
# In your container build file — use placeholder key during asset pipeline compilation
# This avoids embedding live keys in container artifact layers
ARG SECRET_KEY_BASE_DUMMY=1
RUN bundle exec rails assets:precompileThis pattern is the modern equivalent of passing a random value via SECRET_KEY_BASE during the build step. The asset pipeline does not actually use secret_key_base to sign anything during precompilation — it just needs the framework to boot successfully. Using the placeholder approach is considered the right way to handle this in recent versions and later.
Revoking, Rotating, and Securing Your generate rails secret_key_base Process
When and Why to Revoke or Rotate the Key
Rotating your secret_key_base is necessary when the key has been — or may have been — exposed. Common scenarios include accidental commits to a public repository, a compromised host context, a former team member departing with access to live key values, or detection by a secret scanning tool reporting occurrences per million commits in your repository history. The GitGuardian documentation classifies rails secret key detection as belonging to the family cryptographic type, category private key, with high recall sensitivity — meaning even partial exposure warrants immediate rotation.
The protection properties of this key in GitGuardian's detector framework are:
- High recall: False (the detector is precise, not exhaustive)
- Validity check available: False (cannot be automatically validated against a live system)
- Analyzer available: False (no automated analysis of scope)
- Revoker available: False (the framework does not have an external revocation endpoint — you must rotate manually)
- Occurrences found for one million commits: 2.22 (relatively uncommon in public repos — when found, it is almost always a real secret)
- Prefixed: False (the value itself carries no recognizable prefix, making key detection harder)
Steps to Safely Revoke the Secret
Rotating an exposed key requires care to avoid breaking active user contexts more disruptively than necessary. Modern versions support rotate configurations on cookie verifiers, which allow you to accept both the old and new key during a transition window — this is the graceful way to handle key rotation without instantly invalidating every user context.
Here is the full process to revoke the secret safely:
- Generate new secret: Run
rails secret(or the SSL command if the runtime is unavailable) to produce a new random key value. Store the old secret_key_base value temporarily. - Add rotation config (optional grace period): In your app setup or an initializer, configure verifiers to accept the old key during a transition window using
rotate defaultsandclear rotationsafter the window closes. - Update your credential store: Run
rails credentials:editand update thesecret_key_basevalue, or update theSECRET_KEY_BASEvalue in your host or secrets management system. For the env key and key path approach in multi-context setups, use theencrypted(path, key_path:, env_key:)method signature provided byEncryptedConfiguration. - Redeploy: Push your changes and trigger a full deployment. With the rotation setup in place, existing user contexts signed with the old key remain valid temporarily while new ones use the updated key.
- Remove rotation after transition: After a suitable window (typically one session TTL period), remove the old key from the rotation setup and redeploy. At this point, any remaining user contexts using the old secret_key_base will be invalidated.
# config/application.rb — rotation setup during secret_key_base transition
module MyApp
class Application < Rails::Application
# After updating secret_key_base, add old key to rotations for graceful transition
# Remove this block after the transition window (e.g., 24–48 hours)
config.action_dispatch.cookies_rotations.tap do |cookies|
cookies.rotate :encrypted, secret: ENV["OLD_SECRET_KEY_BASE"]
cookies.rotate :signed, secret: ENV["OLD_SECRET_KEY_BASE"]
end
end
endImpact on Signed Cookies, Encrypted Cookies, and Existing Sessions
Changing secret_key_base without a rotation window has immediate, far-reaching effects on your application:
- Signed cookies — any cookie verified by
ActiveSupport::MessageVerifier(including session data by default) will fail verification and be rejected. Users are effectively logged out. - Protected cookies — values processed by the message encryptor (the encrypted cookie jar) become unreadable. Attempts to decipher them produce errors, and the cookie is discarded.
- Token generation — any token produced using the application's key derivation system (such as CSRF tokens, remember-me tokens, or password reset tokens) will be invalidated immediately.
- Session integrity is actually improved by the rotation — an attacker holding a forged session token built with the compromised key cannot use it after rotation.
- Authenticated signed messages sent via email or stored in the database (e.g., signed GlobalID strings) may also become invalid if they were signed using a derived key.
This impact is why you should update secret_key_base carefully rather than abruptly. For long-running apps with large user bases, a grace period is essential to minimize disruption while maintaining application integrity. The messageverifier rotation API introduced in recent versions makes this transition significantly cleaner than in earlier releases — in version 5.2-era apps, abrupt rotation was the only option.
Stack internal reminder: If you are running multiple app instances behind a load balancer, ensure all instances receive the updated secret_key_base simultaneously — or use a shared credential store. A mixed deployment where some hosts use the old key and others use the new key will cause intermittent verification failures as requests are routed to different backends. This is a common but subtle deployment pitfall for stored key rotation.
For precompile assets during CI or build steps where the app must boot without real key values, setting SECRET_KEY_BASE_DUMMY=1 is the safe alternative. Note that having the runtime available on your base VM is required to use the CLI approach; use the system SSL command as an alternative on systems where only OpenSSL and Perl are available.
In practical terms:
- The master key protects your stored config at rest — it is used once at startup to decrypt the encrypted config file.
- secret_key_base is used continuously at runtime to sign session data, verify authenticated messages, and produce cipher instances via
ActiveSupport::MessageEncryptorandActiveSupport::MessageVerifier. - Rotating the master key requires re-protecting your stored config but does not invalidate existing user contexts — as long as secret_key_base itself does not change.
- Rotating secret_key_base invalidates all active user contexts and protected cookie values, regardless of whether the master key changes.
The recommended way to retrieve secret_key_base in your codebase — confirmed by the official API documentation and resources like Saeloun's engineering blog — is always Rails.application.secret_key_base, which resolves the active context value through the full priority chain. Avoid calling Rails.application.secrets.secret_key_base directly, as this is phased out in version 7.1 and triggers a removal notice pointing toward upcoming deprecation in a future release. This learning is widely shared in the developer community as an important migration step for any team still on older patterns. The divergence between the credentials API and the legacy secrets API is one of the most impactful phased-removal changes in recent framework history, and staying current with it is essential for backend teams maintaining long-running applications.
Frequently Asked Questions
- How is this different from rails secret?
- It produces an identical format -- 64 random bytes encoded as 128 lowercase hex characters -- computed in your browser instead of via the Rails command line. Use this when you need a value quickly without a local Rails installation or terminal access.
- Where should I put the generated value?
- As of Rails 5.2+, store it via encrypted credentials (bin/rails credentials:edit, under secret_key_base:) rather than a plain environment variable or config/secrets.yml -- the credentials system is the current recommended approach and keeps the value encrypted at rest in your repository.
- What does secret_key_base actually protect?
- It's the root key Rails uses to derive signing and encryption keys for session cookies, CSRF tokens, and any data processed through ActiveSupport::MessageEncryptor or MessageVerifier. Anyone who obtains it can forge signed cookies or decrypt encrypted session data for your application.
- What happens if I change secret_key_base?
- Every existing session and any previously signed or encrypted cookie value becomes invalid immediately -- all logged-in users will be signed out. Treat rotation the same way you'd treat any other credential rotation: deliberate, and expected to force re-authentication.
- Is secret_key_base the same as the Rails master key?
- No -- the master key (config/master.key) is used once at boot to decrypt your encrypted credentials file, which is where secret_key_base itself is typically stored. They're related but distinct: rotating the master key alone doesn't invalidate sessions, but rotating secret_key_base always does.