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 ![]()