How to Integrate Cloudflare Turnstile with Devise in Ruby on Rails 7 (Step-by-Step Guide)
October 21, 2024
In this article, we’ll walk you through integrating Cloudflare Turnstile, a user-friendly CAPTCHA alternative, with Devise in a Ruby on Rails 7 application. This guide ensures your sign-up page is protected from spam and bots while using Rails credentials to manage sensitive keys securely.
Prerequisites
- A Cloudflare account with access to the Turnstile service.
- Site Key and Secret Key from the Cloudflare Turnstile dashboard.
- A working Rails 7 application using Devise for user authentication.
Step 1: Configure Cloudflare Credentials in Rails
-
Open the Rails credentials editor:
EDITOR="nano" bin/rails credentials:edit
-
Add your Turnstile Site Key and Secret Key under the
cloudflare
section:cloudflare: turnstile_site_key: your_site_key_here turnstile_secret_key: your_secret_key_here
-
Save and close the editor.
Step 2: Add the Turnstile Widget to the Sign-Up View
-
Generate Devise views if you haven’t already:
rails generate devise:views
-
Open the sign-up form located at:
app/views/devise/registrations/new.html.erb
-
Add the Turnstile widget to the form:
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= devise_error_messages! %> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true %> </div> <div class="field"> <%= f.label :password %><br /> <%= f.password_field :password, autocomplete: "off" %> </div> <div class="field"> <%= f.label :password_confirmation %><br /> <%= f.password_field :password_confirmation, autocomplete: "off" %> </div> <div class="cf-turnstile" data-sitekey="<%= Rails.application.credentials.dig(:cloudflare, :turnstile_site_key) %>"></div> <div class="actions"> <%= f.submit "Sign up" %> </div> <% end %> <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
Step 3: Customize the Devise Registrations Controller
-
Create a custom RegistrationsController:
rails generate controller users/registrations
-
Modify the generated file at
app/controllers/users/registrations_controller.rb
:require 'net/http' require 'uri' require 'json' class Users::RegistrationsController < Devise::RegistrationsController def create turnstile_token = params["cf-turnstile-response"] unless verify_turnstile(turnstile_token) flash[:alert] = "Turnstile verification failed. Please try again." redirect_to new_user_registration_path and return end super end private def verify_turnstile(token) uri = URI("https://challenges.cloudflare.com/turnstile/v0/siteverify") response = Net::HTTP.post_form(uri, { "secret" => Rails.application.credentials.dig(:cloudflare, :turnstile_secret_key), "response" => token }) result = JSON.parse(response.body) result["success"] rescue StandardError => e Rails.logger.error "Turnstile verification failed: #{e.message}" false end end
-
Update the routes to use the custom RegistrationsController. In
config/routes.rb
, modify the Devise setup:devise_for :users, controllers: { registrations: 'users/registrations' }
Step 4: Restart the Rails Server and Test the Integration
-
Start your Rails server:
rails server
-
Visit the sign-up page at
/users/sign_up
. Ensure that:- The Turnstile widget is visible.
- Users cannot sign up unless they complete the Turnstile challenge.
- Invalid challenges display the appropriate error message.
Conclusion
Integrating Cloudflare Turnstile with Devise in Rails 7 adds a seamless layer of security to your sign-up page. By using Rails credentials, you keep sensitive keys secure, enhancing both application safety and maintainability.
This approach ensures a bot-free user experience while leveraging the simplicity of Devise for authentication. If you encounter any issues or need further customization, refer to the Cloudflare Turnstile documentation or check your Rails logs for errors.
Enjoyed the guide? Share it with other Rails developers looking to secure their applications with Cloudflare Turnstile!
Happy coding! 🎉