Skip to content

Instantly share code, notes, and snippets.

@teawithfruit
Created December 15, 2021 13:58
Show Gist options
  • Save teawithfruit/b76bf0d045958e25fbfdf9a28141c259 to your computer and use it in GitHub Desktop.
Save teawithfruit/b76bf0d045958e25fbfdf9a28141c259 to your computer and use it in GitHub Desktop.
Migrate accounts with pbkdf2 passwords from MySQL to Keycloak
const mysql = require('mysql')
const { curly } = require('node-libcurl');
const querystring = require('querystring');
const host = 'URL_TO_KEYCLOAK'
const realm = 'REALM_NAME'
async function migrate() {
var connection = mysql.createConnection({
host: 'HOST', // Insert your database host.
user: 'USER', // Insert your database user.
password: 'PASSWORD', // Insert your database password.
database: 'DATABASE_NAME' // Insert your database name.
})
connection.connect()
let account = await new Promise(resolve => {
// Update this qurey to get the accounts from your database.
connection.query('SELECT id, username, email, password, salt FROM account', (error, results) => {
if(error) throw error;
resolve(results)
})
})
for(let a of account) {
const email = a.email
const username = a.username
const password = Buffer.from(a.password, 'hex').toString('base64')
const salt = Buffer.from(a.salt).toString('base64')
try {
const { data } = await curly.post(`${host}/realms/master/protocol/openid-connect/token`, {
POST: true,
SSL_VERIFYPEER: false,
POSTFIELDS: querystring.stringify({
username: 'KEYCLOAK_ADMIN_USER', // Insert your keycloak admin user.
password: 'KEYCLOAK_ADMIN_PASSWORD', // Insert your keycloak admin password.
grant_type: 'password',
client_id: 'admin-cli'
}),
httpHeader: [
'Content-Type: application/x-www-form-urlencoded',
'Accept: application/json'
],
})
await curly.post(`${host}/admin/realms/${realm}/users`, {
POST: true,
SSL_VERIFYPEER: false,
POSTFIELDS: JSON.stringify({
email: email,
emailVerified: true,
username: username,
enabled: true,
attributes: {},
credentials: [
{
credentialData: JSON.stringify({
hashIterations: 2048, // Change this if you have used a different number of interations.
algorithm: "pbkdf2-sha512" // Change this if you used a different pbkdf2 setting.
}),
secretData: JSON.stringify({
salt: salt,
value: password,
additionalParameters: {}
}),
temporary: false,
type: "password"
}
]
}),
httpHeader: [
'Content-Type: application/json',
'Accept: application/json',
`Authorization: Bearer ${data.access_token}`
],
})
const response = await curly.get(`${host}/admin/realms/${realm}/users?email=${email}`, {
SSL_VERIFYPEER: false,
httpHeader: [
'Content-Type: application/json',
'Accept: application/json',
`Authorization: Bearer ${data.access_token}`
]
})
// Change or delete this query if you want to store the keycloak id in your database.
await new Promise(resolve => {
connection.query('UPDATE account SET keycloak = ? WHERE id = ?', [response.data[0].id, a.id], (error, results) => {
if(error) throw error;
resolve(results)
})
})
console.log(a.email);
} catch(e) {
console.log(e);
}
}
connection.end()
console.log('DONE');
}
migrate()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment