Migration from Keycloak with argon2 passwords to Auth0

Hello,
I am currently using Keycloak 26.2.3 with argon2 password encryption. The parameters are:

{
  "hash_iterations": 5,
  "algorithm": "argon2",
  "additionalParameters": {
    "hashLength": ["32"],
    "memory": ["7168"],
    "type": ["id"],
    "version": ["1.3"],
    "parallelism": ["1"]
  }
}

How can I specify the password in the import with custom_password_hash? All combinations do not work.

Working through all the existing documentation snippets, my approach would be to transform this example

{
  "value": "SOMEHASHWITHTRAILING=",
  "salt": "SOMESALTWITHTRAILING==",
  "additionalParameters": {}
}

to this custom_password_hash

"custom_password_hash": {
  "algorithm": "argon2",
  "hash": {
    "value": "$argon2id$v=19$m=7168,t=5,p=1$SOMESALTWITHOUTTRAILING$SOMEHASHWITHOUTTRAILING"
  }
}

I can import the users this way, but I always get the error:

"error": {
  "message": "Password change required.",
  "reason": "Verification failed for the provided custom_password_hash: {'algorithm':'argon2','hash':{'value':'$argon2id$v=19$m=7168,t=...'},'salt':{'value':''}}"
}

What am I doing wrong? Thanks for the help in advance

By the way, I wrote this script to convert my export:

import json


result = []

with open('keycloak-export.json', 'r') as file:
    data = json.load(file)

for user in data['users']:
    if 'service-account' in user['username']:
        continue  # Skip service accounts for now

    pw_data = next((p for p in user['credentials'] if p['type'] == 'password'), None)
    if pw_data is None:
        raise ValueError(f"User {user['username']} does not have a password credential.")
    
    pw_sec = json.loads(pw_data['secretData'])
    pw_cred = json.loads(pw_data['credentialData'])

    if pw_cred['algorithm'] != 'argon2':
        raise ValueError(f"User {user['username']} does not have an argon2id password credential.")
    if pw_cred['additionalParameters']['version'] != ['1.3']:
        raise ValueError(f"User {user['username']} does not have an argon2id v1.3 password credential.")
    if pw_cred['additionalParameters']['type'] != ['id']:
        raise ValueError(f"User {user['username']} does not have an argon2id password credential of type 'id'.")
    
    pw_m = pw_cred['additionalParameters']['memory'][0]
    pw_t = pw_cred['hash_iterations']  # This should be in camelCase, but it's a bad word
    pw_p = pw_cred['additionalParameters']['parallelism'][0]
    pw_salt = str(pw_sec['salt']).rstrip('=')
    pw_hash = str(pw_sec['value']).rstrip('=')
    
    result.append({
        "username": user['username'],
        "email": user['email'],
        "email_verified": user['emailVerified'],
        "given_name": user['firstName'],
        "nickname": user['firstName'],
        "family_name": user['lastName'],
        "name": f"{user['firstName']} {user['lastName']}",
        "custom_password_hash": {
            "algorithm": "argon2",
            "hash": {
                "value": f"$argon2id$v=19$m={pw_m},t={pw_t},p={pw_p}${pw_salt}${pw_hash}"
            }
        }
    })

with open('auth0-import.json', 'w') as file:
    json.dump(result, file, indent=4)
print(f"Exported {len(result)} users to auth0-import.json")

Hi @Pedigree4163,

Welcome to the Auth0 Community!

Try adding the encoding to the hash section as shown here:

"custom_password_hash": {
    "algorithm": "argon2",
    "hash": {
        "value": f"$argon2id$v=19$m={pw_m},t={pw_t},p={pw_p}${pw_salt}${pw_hash}",
        "encoding": "utf8"
    }
}

Let us know if this fixes the issue.

Have a good one,
Vlad

Hi @vlad.murarasu,
thanks for your help, unfortunately it doesn’t work either.
I’m guessing it’s because of how Keycloak handles input? But Argon2 is actually a standard, isn’t it?
Thank you