I am attempting to import users, including their passwords, from Discourse to Auth0. I’m following these guides:
https://auth0.com/docs/users/guides/bulk-user-imports
Step 1 Export users from Discourse
Using Discourse’s nifty Data Explorer Plugin, I’ve used this query to generate a list that includes email
, email_verified
and password_hash
.
Query
SELECT
user_emails.email,
users.active as email_verified,
concat(
'$pbkdf2-sha256$i=64000,l=32$',
users.salt,
'$',
replace(encode(decode(users.password_hash, 'hex'), 'base64'), '=', '')
) as password_hash
FROM users
INNER JOIN user_emails
ON users.id = user_emails.user_id
AND user_emails.primary IS TRUE
AND users.id > 0
Note that I’ve based the PHC string generation on the example given by the Discourse team. As far as I can tell this follows the PHC standard. Here’s an example string
$pbkdf2-sha256$i=64000,l=32$eedf758e855bf13f96f9c48c14d486fb$3t2t87idnzb3Xzqwi0zXn95uJBwKZlo5Sk4yCg4jxR8
Password hashing in Discourse is performed here. And the relevant configuration is here. The hashing and configration have not changed since the PHC “how-to” doc linked above was written.
Step 2 Create users JSON file
I’ve used this ruby script to convert the Discourse users JSON to an Auth0 users JSON
Generate Auth0 JSON
#!/usr/bin/ruby
require 'json'
input = JSON.parse(File.read(ARGV[0]))
output = []
input["rows"].each do |row|
output.push(
email: row[0],
email_verified: row[1],
custom_password_hash: {
algorithm: "pbkdf2",
hash: {
value: row[2],
encoding: "utf8"
}
}
)
end
File.open("output.json", "w") do |f|
f.write(output.to_json)
end
Here’s an example user JSON produced by that script
{
"email": "angus+1@fake-email.com",
"email_verified": true,
"custom_password_hash": {
"algorithm": "pbkdf2",
"hash": {
"value": "$pbkdf2-sha256$i=64000,l=32$eedf758e855bf13f96f9c48c14d486fb$3t2t87idnzb3Xzqwi0zXn95uJBwKZlo5Sk4yCg4jxR8",
"encoding": "utf8"
}
}
}
Step 3 Post users JSON file to Auth0
I’ve used this ruby script to post the JSON file to Auth0
Create Auth0 Import
#!/usr/bin/ruby
require 'rest-client'
response = RestClient.post(
"https://***.auth0.com/api/v2/jobs/users-imports", {
users: File.new("output.json"),
connection_id: "***",
send_completion_email: true
}, {
"authorization": "Bearer ***",
"content-type": "multipart/form-data"
}
)
puts response.body
The import succeeds with no errors. Upon completion, I see the users I’ve imported in the Auth0 dashboard, with the correct email
and email_verified
attributes.
Step 4 Attempt to sign in
On attempting to sign in with an imported user I’m getting this error in the UI:
And this error in the logs:
"error": {
"message": "Password change required.",
"reason": "Verification failed for the provided custom_password_hash: {'algorithm':'pbkdf2','hash':{'value':'$pbkdf2-sha256$i=64000,l=3...','encoding':'utf8'},'salt':{'value':''}}"
Aside from an issue with the PHC string which I’m not seeing, the only other thing that stands out is that there is an empty “salt” value in the error.reason
.
'salt':{'value':''}
As you’ll notice in the users JSON file example, no seperate salt value has been included in the import file. Perhaps this is just a standard logging output, but that could be the issue.
Any pointers or hints would be much appreciated