I’m importing user from an old Firebase project to another.
The import ends successfully with no errors but from the new application, user cannot authenticate with same credentials and the following error is returned:
[auth/wrong-password]: The password is invalid or the user does not have a password.
This is the code I’m using to migrate users:
private async Task<MigrationResult> MigrateUsers(AbstractFirebaseAuth authFrom, AbstractFirebaseAuth authTo, UserImportOptions options, string? pageToken = null, MigrationResult? result = null)
{
result ??= new MigrationResult
{
Success = false,
SuccessCount = 0,
FailureCount = 0
};
try
{
/* DOCS
* - GET PASSWORD HASH AND SALT: https://firebase.google.com/docs/auth/admin/manage-users?hl=en#password_hashes_of_listed_users
*/
var usersToMigrate = await authFrom.ListUsersAsync(new ListUsersOptions
{
PageSize = 1000,
PageToken = pageToken
}).ReadPageAsync(1000);
var users = usersToMigrate.Select(u => new ImportUserRecordArgs
{
Uid = u.Uid,
PasswordHash = Encoding.ASCII.GetBytes(u.PasswordHash),
PasswordSalt = Encoding.ASCII.GetBytes(u.PasswordSalt),
Email = u.Email,
EmailVerified = u.EmailVerified,
PhoneNumber = u.PhoneNumber,
DisplayName = u.DisplayName,
PhotoUrl = u.PhotoUrl,
Disabled = u.Disabled,
CustomClaims = u.CustomClaims,
UserProviders = u.ProviderData.Select(p => new UserProvider
{
Uid = p.Uid,
DisplayName = p.DisplayName,
PhotoUrl = p.PhotoUrl,
Email = p.Email,
ProviderId = p.ProviderId
})
});
var importResult = await authTo.ImportUsersAsync(users, options);
_logger.LogInformation($"{nameof(MigrateUsers)}: Successfully imported {importResult.SuccessCount} users");
if (importResult.FailureCount > 0)
{
_logger.LogWarning($"{nameof(MigrateUsers)}: Failed to import {importResult.FailureCount} users");
foreach (ErrorInfo indexedError in importResult.Errors)
_logger.LogWarning($"{nameof(MigrateUsers)}: Failed to import user at index: {indexedError.Index} due to error: {indexedError.Reason}");
}
result.Success = true;
result.SuccessCount += importResult.SuccessCount;
result.FailureCount += importResult.FailureCount;
if (!string.IsNullOrWhiteSpace(usersToMigrate.NextPageToken))
return await MigrateUsers(authFrom, authTo, options, usersToMigrate.NextPageToken, result);
return result;
}
catch (FirebaseAuthException ex)
{
_logger.LogWarning($"{nameof(MigrateUsers)}: {nameof(FirebaseAuthException)} | {ex.AuthErrorCode} | From tenant {(authFrom is TenantAwareFirebaseAuth ? (authFrom as TenantAwareFirebaseAuth)?.TenantId : "Default")} to tenant {(authTo is TenantAwareFirebaseAuth ? (authTo as TenantAwareFirebaseAuth)?.TenantId : "Default")}", ex);
result.Success = false;
return result;
}
}
and this is the ImportUsersAsync
option object:
var options = new UserImportOptions()
{
Hash = hash
};
where hash
is:
var hash = new Scrypt()
{
Key = Encoding.ASCII.GetBytes("[base64_signer_key from the OLD project]"),
SaltSeparator = Encoding.ASCII.GetBytes("salt separator from the OLD project"),
Rounds = 8,
MemoryCost = 14
}
From the documentation this code should be fine and when the user opens up the new app, all they need to do is sign in again and the password should be rehashed and everything should works fine. But this is not happening.
What am I doing wrong?
Thank you!
2
Answers
@Rainy sidewalks
This is the config in the old project:
In the new project obviously the value for
base64_signer_key
is different but thealgorithm
and other parameters are the same.So I confirm that the Scrypt algorithm is the one used in the old project, based on the screenshot. I confirm that the values of [base64_signer_key from the OLD project] and "salt separator from the OLD project" are correct, I've triple checked this.
Any idea?
1st please verify the following
1.the hash object used for password hashing in the new project is correctly initialized with the values from the old project.
Double-check that the [base64_signer_key from the OLD project] and "salt separator from the OLD project" values are correct and match the values used in the old project.
2.Confirm that the Scrypt algorithm is the correct algorithm used for password hashing in the old project.(possibly it uses different algorithm, such as Bcrypt or PBKDF2)
check the above and let us know