Migrate Rails Devise Users to Firebase Authentication

Image for post
Image for post

My goal for my SaaS gixtra.com (a tool to book and organize concerts) is to delegate as many non-core-business features to external services, so I can focus on the important music business stuff. One milestone to reach this goal is to get rid of doing authentication myself in Devise. Since I find Google’s Firebase offering very appealing, I want to migrate my existing users to Firebase Authentication. Here is how I did it…

Getting started

This is basic Firebase setup stuff, so I will spare you the details.

First I created a new project in Firebase and enabled email authentication. Then I initialized my Rails app, connected it to the newly created Firebase project and chose to use just the Firebase database service.

Now comes the interesting part…

Importing in 2 steps

Importing your Devise users into Firebase Auth essentially takes 2 steps:

  1. Export your user data into an appropriately formatted JSON file
  2. Import that file via the Firebase CLI

1. Exporting Devise users to JSON

First we need to export our users into a JSON file, which will later be picked up by Firebase in the second step. I created a rake task in my Rails app for that:

namespace ‘gixtra’ do  desc “Export user DB to JSON for import via Firebase Auth”
task export_users: :environment do
puts ‘1/2 Exporting users to users.json’
data = {users: []}
open(‘tmp/users.json’, ‘w’) do |f|
User.find_each do |user|
ju = {
localId: user.id,
email: user.email,
emailVerified: user.confirmed_at ? true : false,
passwordHash: Base64.encode64(user.encrypted_password),
displayName: user.name,
photoUrl: user.image.try(:url),
createdAt: user.created_at ? user.created_at.to_i * 1000 : nil,
lastSignedInAt: user.last_sign_in_at ? user.last_sign_in_at.to_i * 1000 : nil,
phoneNumber: user.mobile
}
data[:users] << ju
end
f.puts data.stringify_keys.to_json
end

I basically go through all users and transform their attributes to the format needed by Firebase. The final JSON is then stored in a file at the root of my Rails app as “tmp/users.json”. Feel free to adapt which attributes you need. You can find the Firebase Auth accepted fields in their online documentation.

A few things to note about this code:

  • The rake task needs to depend on :environment so that it has access to our full Rails app environment
  • I use User.find_each so the process doesn’t have to keep all users (potentially many thousands) in memory.
  • The passwordHash has to be base64 encoded; so I encode the encrypted_password of Devise.
  • I am cautious about attributes eventually being null . I use try to gracefully handle these, so that a null attribute won’t crash my rake task halfway through the database.
  • Timestamps have to be converted to milliseconds. Rails’ DateTime.to_i method delivers seconds, so I simply multiply this value by 1000 (no need to be more accurate than seconds on these fields).
  • I store the file in the tmp directory, so that I can also run this rake task on heroku.

2. Import via Firebase CLI

Now that we have our users.json we can hand that over to Firebase. You can create a second rake task for that, but in my case I simply added the following lines to the end of the rake task from above:

puts ‘2/2 Importing users into Firebase’
sh “firebase auth:import tmp/users.json — hash-algo=BCRYPT — hash-key=’#{Devise.secret_key}' — rounds=10”

The Firebase Authentication CLI is well documented with all its parameters. Let me explain the ones I used:

  • tmp/users.json is obviously the file we created in step 1
  • The default hash algorithm used by Devise is BCRYPT
  • The hash-key is the secret_key you will find at the top of your devise initializer file (mine is at config/initializers/devise.rb ). You could just copy it from there, but I fetch it directly through the Devise module.
  • In my case Devise seems to use 10 rounds for hashing passwords. You can see this at the beginning of each encrypted_password value ($2a$10… in my case, which indicates 10 rounds).

Go!

That’s all for the preparation. Now I simply run my rake task and I see the following output for my development seed data:

→ rake gixtra:export_users1/2 Exporting users to users.json2/2 Importing users into Firebasefirebase auth:import users.json — hash-algo=BCRYPT — hash-key=’ea7e*****' — rounds=10Processing users.json (47922 bytes)Starting importing 124 account(s).✔ Imported successfully.

Now go and check your users tab in your Firebase console on the web. You should see all your users imported nicely 😁.

Hope this description of my process helps you to migrate your users from Devise to Firebase Auth. If you encounter any errors, have any suggestions or questions, please leave me a comment.

Written by

Agile Coach, Business Innovator, Software Engineer, Musician

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store