No Salt and no DigestHa1Hash in V5?

I started a new project in VS using the ServiceStack templates. It installed V5 libraries. I use code, that is working fine under V4 to create users, store them on Redis and authenticate them. So I have created my own implementations of a CredentialsAuthProvider and IUserAuth. Under V5 my TryAuthenticate implementation does not work anymore.

After doing some debugging I saw, that under V5 my Users do not have a Salt anymore, its NULL! Here is what I see on my Redis server when creating a User with V5:

  "Id": 1,
  "PasswordHash":    "AQAAAAEAACcQAAAAEHBporPVLHPxzcO4DN1REjElwisOBbAoN6jB9UIfjaqp5UvhcfM+YpmobgxRdd3Tqg==",
"Roles": [
"Permissions": [],
"InvalidLoginAttempts": 0,

The properties Salt and DigestHa1Hash are missing!

Under Version 4 (stored on the same Redis server, different database of course) it looks like so:

"Id": 1,
"Salt": "lXjzNw==",
"PasswordHash": "PZfgSEPU8utcF1KesYZLkcOvUDG6q3fkU3BvZeu64AI=",
"DigestHa1Hash": "7dfbd32f8809a495ff9865f6b88ce463",
"Roles": [
"Permissions": [],

In my TryAuthenticate implementation I do:

var authRepo = (IUserAuthRepository)HostContext.TryResolve<IAuthRepository>();
var saltedHash = HostContext.Resolve<IHashProvider>();
user = (LsUser)authRepo.GetUserAuthByUserName(userName);
if (user == null)
    throw HttpError.NotFound("User '{0}' not found. Please try again.".Fmt(userName));
var logonSuccess = saltedHash.VerifyHashString(password, user.PasswordHash, user.Salt);
if (logonSuccess)
{ ... }

Since user.Salt is NULL, VerifyHashString is of course false all the time.

Did anything change in V5 that has an impact on user creation or do I miss something else??


Yes ServiceStack has switched to use ASP.NET’s Identity v3 PBKDF2 Password Hashing Algorithm, there’s still a salt but it’s stored in the same field as the password hash, along with other params.

The release notes includes info on Digest Auth Hashes and what Auth Repositories need to do to utilize the new behavior, e.g. they should now use:

if (userAuth.VerifyPassword(password, out var needsRehash))
    this.RecordSuccessfulLogin(userAuth, needsRehash, password);
    return true;

Sorry just found in the last readme the info about PBKDF2 Password Hashing implementation