Migrate users from Firebase to own database (with password)
Tags: firebase, authentication, migration, password
Published: 2021-11-01 19:25:51

_I don’t know if this thing is obvious or already doable, but the company for which I worked briefly had this problem, and I came up with a solution that I’m going to share here._

I’m not going to discuss the reasons to do so, you may have your own reasons for the title, and neither I’m saying that the method in this article is the best or worst. But, it worked, and should be working at the time of writing this article.

## A Brief Context
The company for which I came up with the solution for this had their own server, and were using Firebase to handle their users' authentication. But later on they planned to make users login/signup using their own server. To create a custom auth system is not a big deal, but the important thing was to make it work for existing users too, and by that time the amount of users signed up via Firebase was tremendous.
In their system with Firebase, after a user signed up, they stored user’s data on their own database too (except the password), and used Firebase auth token for all authorised requests, which was provided by Firebase upon user login (the login request was sent directly from client side to Firebase), and that token was checked for validity on their server itself using a middleware.

## The Problem
Now in the new system, user will signup directly on server, and auth token will be generated by server itself upon user login, as the login info will be in their own database, without the intervention of Firebase. But the existing user who signed up using the previous system will face problems in login, as the server won’t be able to verify their password because of the absence of their password in database.
So the problem with new system converged to the absence of existing users' passwords, which was managed by Firebase and it won’t provide it to anyone to store it anywhere else.

## Early Approach
A suggestion was made that a separate email could be sent to all Firebase users with a password reset link, so that they’ll feed their password in the database themselves (which will be hashed before storing, obviously), and consequently they will be able to login via new system.
No doubt that the above approach will do the job. But, at least in my point of view, this approach is flawed, primarily, ethically. Why?
- You don’t send emails to your own users to reset their password until and unless there’s a reasonable related security breach which you’ll have to announce beforehand.
- You don’t send emails with link to reset password to your own users, because that’s what crackers (or hackers) do with your users (the wrong impression).
- Even if you do send emails to tell them to reset their password, there’s no guarantee that everyone will do so, and your password migration process will be left upon the mercy of your users.
- Users don’t want to be bothered with a password reset (many of them don’t change their own passwords for years). So you cannot expect them to understand your reasons and thus follow, because in current scenario, it’s not even a problem from their side.
- And many more reasons to convince you that this approach isn’t good.

So that’s why this approach was not reliable in my point of view. But the point to be considered from this method is it’s decentralised approach, which is letting the users do our job. The main drawback to tackle in this approach was to rely on users' choice to do this for us. And also, we cannot wait for all users to change password first, and then deploy the new system of authentication and by that time more users will signup via old system, demanding more password reset emails. Also, taking the server down for maintenance is not a solution (should always be the last method to opt for).

## The Final Solution
The solution that made its way to be the final took the idea of decentralisation from the early approach, that is, letting the users do this for us, and tackled its associated mentioned problems.
The following steps describe what was eventually done with help from other developers as the final solution.
We changed the old system with new one first in code, that is, the new system was implemented for authentication in separate branch in which everyone was working (un-deployed).
After the login and signup process was changed from sending request to Firebase to sending request to own sever, and we retained the login function of Firebase which returns the Firebase auth token upon successful login as secondary step, however we didn’t use it for actual authorisation.
The theory was —
- A user will enter their credentials (including raw password) normally while login, and on submission, the credentials will be sent to the new login server, which will return a token upon successful login, and the user will proceed normally as authorised user.
- If the new login endpoint returns an error, it is then inferred as user’s password not being present in our database (it may also imply that user doesn’t exist).
- Then a next login request will be automatically sent directly to Firebase (the old way), and if it returns error, it will imply that user doesn’t exist, or user has entered the wrong credentials, and error will be shown to user in that case. But if it returns success, with Firebase auth token, it will imply that user has not yet migrated, and the user’s password is yet to be saved in database (user eligible for migration).
- A next request will take the credentials and the Firebase auth token with it to an endpoint which will verify the Firebase token using the old server side middleware, and if token is valid, it will imply that incoming credentials are valid, including the raw password, therefore it is safe to save the password (after hashing it) for the user (from incoming credentials) in database. And it will be done, marking successful migration of that user. This endpoint will also return new auth token so that user can proceed as in step 1.
- Next time if the same user will try to login, only the step 1 will be used if credentials are right, as the server will be able to compare the incoming credentials including password with the one that exists in database for that user. After that, user will proceed as authorised user in new auth system.
- The above all steps will happen only and only once when an unmigrated user tries to login. The correct credentials will automatically migrate the user without their knowledge, and thereafter, Firebase will no longer be involved in authentication for that particular user.

The steps 1 to 5 will take place upon login form submission only, accordingly (during the loading animation, if there).
The base problem in early approach was that the user was knowingly involved in their migration. This was tackled by the final solution as user unknowingly migrates themselves while logging in, and they don’t need to know that they’ve been migrated from Firebase auth to server auth. Also, we are not relying upon user’s mercy, as login is something every user will do at some point of time. Therefore, depending upon the traffic of users' login requests on server, everyone’s migration will take place in time. The point to be noted is, no one from the company side was required to make any changes in database or Firebase. And ofcourse, in step 4, after successful migration, things like deleting the user from Firebase can be performed to clean up Firebase’s involvement properly, and you can alert users about the automatic change if you want to (we didn’t do that).

## Execution
So we went on with the final solution, and deployed the new code changes, none of the user was alerted, a few of us logged in as unmigrated users (we had our accounts made with old system), and our accounts got successfully migrated, fulfilling all expectations of the solution theory.

## Aftermath or something
The steps included in login submission meant for migration can be removed later on when all the users have migrated themselves, which can be checked from Firebase (if you auto delete users from Firebase upon migration). If some users still remain unmigrated after significant amount of time (they may not have logged in anytime after new auth system deployment), then you don’t need to follow a separate policy. Instead, you can follow your existing policy for these kind of zombie users (alerting them to login or lose account, or whatever you do with these kind of accounts). And for signup, it’s obvious that new users will be registered directly using server instead of Firebase.

Now you, the reader, may have thought of another solution, maybe a better one, and therefore I had mentioned in the beginning of this article that in no way I’m declaring this as the best method out there. But, we did it, and it worked, and should be working at the time of writing this article.

Originally posted [here](https://link.medium.com/xiVgJfZXPkb).