Password Rehashing During Login
Security requirements change over time. A hash that was acceptable a few years ago may no longer meet your current policy.
Use login-time rehashing to upgrade stored password hashes gradually, without forcing a global password reset.
Why Rehash During Login
Use this approach when you need to:
- Migrate from plaintext or weak legacy hashes to stronger formats
- Increase PBKDF2 cost (
rounds) or Argon2 cost (memory_kib,iterations,parallelism) - Keep backend data aligned with current security policy
With login-time rehashing, Radiator only writes a new hash after a successful authentication. Users who never log in are not modified.
Rehash Pattern
A safe rehash flow has four steps:
- Authenticate user against the currently stored password hash.
- In post-authentication, check if the stored value already matches your target format.
- If not, hash the verified plaintext credential (
auth.password) with the target settings. - Persist the new hash to your backend.
Use auth.password as the input for rehashing. This value represents the verified credential from the current PAP login attempt.
Example: Rehash to PBKDF2-SHA512
This example upgrades accounts to {pbkdf2-sha512} after successful PAP authentication.
backends {
radiatordb "CUSTOMER_DB" {
server "primary" {
host "db.example.com";
port 5432;
database "radiator";
username "radiator";
password env.DB_PASSWORD;
}
collection "customers" {
roles {
read "support";
write "ops";
}
key {
field {
name "Username";
type text;
}
}
}
query "FIND_USER" {
collection "customers";
key aaa.identity;
}
put "UPDATE_PASSWORD" {
collection "customers";
key aaa.identity;
bindings {
password = auth.password | password_hash("pbkdf2_sha512", rounds=300000);
}
}
}
}
aaa {
policy "BASIC_AUTH" {
conditions all {
aaa.protocol == protocol.RADIUS;
}
handler "PAP" {
@authentication {
backend {
name "CUSTOMER_DB";
query "FIND_USER";
@once {
user.password = doc | jsonpath("$.password");
}
}
must pap;
}
@post_authentication {
if all {
user.password !starts "{pbkdf2-sha512}";
} then {
backend {
name "CUSTOMER_DB";
query "UPDATE_PASSWORD";
}
}
}
}
}
}
The @once pipeline copies the stored hash to user.password. In
post-authentication, user.password still holds the stored hash, so the
condition checks its format before UPDATE_PASSWORD writes the new hash.
The put operation replaces the stored document with the document that its
bindings block builds. If the customer documents contain other fields, add a
binding for each field that the document must keep. See
radiatordb put.
For algorithm formats and option details, see Password Hashing.