I am trying to migrate my users (on a system using bcrypt) to firebase, using auth:import. I can't seem to get the bcrypt mode to work and was hoping for a suggestion or working example.
Here's an example:
Let's assume a password of "none".
If we go here: https://www.dailycred.com/article/bcrypt-calculator
and create a bcrypt for that password with 10 rounds, we will get something like this:
$2a$10$Kuvv6ATRsbtHnJJHB359WeKrC6ImbEzY0wtCmB21KS39Cw5sMecMK
If we deconstruct the bcrypt above, using this template:
$2a$10$TwentytwocharactersaltThirtyonecharacterspasswordhash
$==$==$======================-------------------------------
we get:
password hash: KrC6ImbEzY0wtCmB21KS39Cw5sMecMK
salt: Kuvv6ATRsbtHnJJHB359We
bcrypt already has these components base64 encoded, thus we should not have to
base64 encode them to pass to auth:import. This would result in an import object like here:
{
"users": [
{
"localId": "abcd-1234-xyz",
"email": "[email protected]",
"emailVerified": false,
"passwordHash": "KrC6ImbEzY0wtCmB21KS39Cw5sMecMK",
"salt": "Kuvv6ATRsbtHnJJHB359We",
"displayName": "A Person",
}
]
}
Alas, if you use this (asssume the above in a file named userAccounts.json):
firebase auth:import --hash-algo='BCRYPT' ./userAccounts.json
the import will succeed, but any logins with "signInWithEmailAndPassword" will fail with this:
{code: "auth/internal-error", message: "{"error":{"errors":[{"domain":"global","reason":"b鈥ode: 7"}],"code":503,"message":"Error code: 7"}}"}
What am I missing?
I see your problem. You don't need to deconstruct bcrypt hash string to get separate salt and resulting hash value. For bcrypt, the whole $2a$10$... should be used as passwordHash and leave salt blank. BTW, there's no need to provide any parameter for bcrypt because cost parameter is already encoded in the whole hash string.
Let's get back to your sample user. We have bcrypt hash string which is $2a$10$Kuvv6ATRsbtHnJJHB359WeKrC6ImbEzY0wtCmB21KS39Cw5sMecMK. We can calculate base64 encoded hash string using the following NodeJS code.
new Buffer('$2a$10$Kuvv6ATRsbtHnJJHB359WeKrC6ImbEzY0wtCmB21KS39Cw5sMecMK').toString('base64')
Result is JDJhJDEwJEt1dnY2QVRSc2J0SG5KSkhCMzU5V2VLckM2SW1iRXpZMHd0Q21CMjFLUzM5Q3c1c01lY01L and this string should be used as passwordHash.
I just tried to upload your sample user with correct passwordHash into my test project and then I can successfully signed in. You can have a try. Thanks.
That worked! Thanks!!!! I sort of wondered it I needed the salt too, since all the info is embedded in the bcrypt. Alas, there was not enough info on the README to determine that. Please add this info the README file to help others as well.
Thanks for the suggestion. I'll try to make the document clearer.
Hi,
I'm getting the exact same error. Also created a user using CLI with bcrypt. I also have not passed a salt and just base64 encoded the bcrypt hash. Are there any other solutions? CLI command used:
firebase auth:import users.json --hash-algo=BCRYPT --project [project-id]
Edit: Contacted firebase support and apparently bcrypt is not supported in the new console.
Hi Jeroen,
Your command line is correct. Could you provide a sample user in your users.json so I can take a look? Thanks.
BTW, bcrypt is not the default hash algorithm in new Firebase but we support importing users with bcrypt hash algorithm.
Yes, here it is:
{
"users": [
{
"localId": "98",
"email": "[email protected]",
"emailVerified": true,
"passwordHash": "JDJ5JDEwJHk3WVFjdzk1VHluejAuREdrSTJKVHVpSi9KeTd4SkZqR2hTblkvWWdmSy55R3RsRHd5dVRT",
"displayName": "Jeroen S",
"providerUserInfo": [
{
"providerId": "facebook.com",
"rawId": "",
"email": "[email protected]",
"displayName": "Jeroen S"
}
]
}
]
}
I've altered the passwordHash for this example and I've also tried this without Facebook providerUserInfo.
Sorry, could you also provide the plain text password for this passwordHash?
Yes let's say I use password 'testtest', bcrypt becomes:
$2y$10$5IlDVsSEpAD.Knsmcx.7d.sc.XL2urf1GK9BiI/3swjf8iTP6Ljfu
and base64:
JDJ5JDEwJDVJbERWc1NFcEFELktuc21jeC43ZC5zYy5YTDJ1cmYxR0s5QmlJLzNzd2pmOGlUUDZMamZ1
I see. The problem is about the 2y prefix in bcrypt hash. Only crypt_blowfish bcrypt implementation use 2y, nobody else adopts this and it's identical to 2a. So solution will be replacing 2y with 2a.
Your example $2y$10$5IlDVsSEpAD.Knsmcx.7d.sc.XL2urf1GK9BiI/3swjf8iTP6Ljfu will be $2a$10$5IlDVsSEpAD.Knsmcx.7d.sc.XL2urf1GK9BiI/3swjf8iTP6Ljfu. And its base64 will be JDJhJDEwJDVJbERWc1NFcEFELktuc21jeC43ZC5zYy5YTDJ1cmYxR0s5QmlJLzNzd2pmOGlUUDZMamZ1. I verified it can work now.
Thanks, it indeed works for me too now!
@wyhao31 what is the default hash algorithm in new Firebase?
It's scrypt
@Jeroeny thank you. Any idea of what are the rounds and the mem-cost used by firebase in this algorithm? Im having a issue related to that here: #253 .
Hi,
I created one user.json with example given by @Jeroeny and I imported that file to firebase with auth:import. Then I did login with credential as email id and password as 'testtest'. User logged in. Then I took backup of users on project, using auth:export in userbackup.json. Here the password hash is different than the passwordhash in user.json. Again I imported userbackup.json to same project. It gives the error which @pillowsoft got. What is solution?
@piya1248
When you successfully login for the first time, Firebase Auth will re-hash user's password using internal implementation of scrypt. That explains why you see different password hash when you export your users again.
If you want to re-import your backup users, you can reach out to Firebase support team and ask them to share the detailed parameters used in your project. After you get all those parameters, you can use auth:import with hash-algo setting to scrypt to import backup users.
If the imported user hasn't login, we have no chance to re-hash the password. When you export users, you'll see no password hash and salt in that user's record. You can also use lastSignedInAt field to tell whether the user login successfully after importation.
A unique salt is stored to re-create hash on input password and then compare with stored passwordhash to see if they match. But the salt is different after each import-export-import operation. It should be fixed, isn't it?
@piya1248
The second time you import users, do you use the Firebase scrypt parameters?
Most helpful comment
I see. The problem is about the
2yprefix in bcrypt hash. Only crypt_blowfish bcrypt implementation use2y, nobody else adopts this and it's identical to2a. So solution will be replacing2ywith2a.Your example
$2y$10$5IlDVsSEpAD.Knsmcx.7d.sc.XL2urf1GK9BiI/3swjf8iTP6Ljfuwill be$2a$10$5IlDVsSEpAD.Knsmcx.7d.sc.XL2urf1GK9BiI/3swjf8iTP6Ljfu. And its base64 will beJDJhJDEwJDVJbERWc1NFcEFELktuc21jeC43ZC5zYy5YTDJ1cmYxR0s5QmlJLzNzd2pmOGlUUDZMamZ1. I verified it can work now.