Rix is the official package layer for Vix.cpp Browse packages
Skip to content

Password Hashing ​

This page explains how to hash and verify passwords with rix/auth.

The examples use the public Rix facade:

cpp
#include <rix.hpp>

and the password helpers through:

cpp
rix.auth.password

Password hashing is used internally by registration and login.

You can also use it directly when you need to test password policy, hash a password, or verify a password against a stored hash.

Basic example ​

Create a file:

bash
mkdir -p ~/rix-auth-password-hashing
cd ~/rix-auth-password-hashing
touch password.cpp

Add:

cpp
#include <rix.hpp>

int main()
{
  rix.debug.print("== rix/auth password hashing ==");

  const auto password = "correct-password";
  auto hashed = rix.auth.password.hash(password);

  if (hashed.failed())
  {
    const auto &error = hashed.error();
    rix.debug.eprint(
        "auth error:",
        rix.auth.error.to_string(error),
        error.message()
    );
    return 1;
  }

  const bool valid = rix.auth.password.verify(password,hashed.value());
  const bool invalid = rix.auth.password.verify("wrong-password",hashed.value());

  rix.debug.print("hash:", hashed.value());
  rix.debug.print("valid password:", valid ? "yes" : "no");
  rix.debug.print("wrong password:", invalid ? "yes" : "no");

  if (!valid || invalid)
  {
    rix.debug.eprint("ERROR:", "password verification failed");
    return 1;
  }

  rix.debug.print("OK:", "password verification successful");

  return 0;
}

Run it:

bash
vix run password.cpp

If Rix is not available yet for single-file usage:

bash
vix install -g rix/rix
vix run password.cpp

Expected output ​

The output should look like this:

txt
== rix/auth password hashing ==
hash: ...
valid password: yes
wrong password: no
OK: password verification successful

The hash value will be different between runs.

Password hashing uses random salt, so the same password should not produce the same encoded hash every time.

Hash a password ​

Use:

cpp
auto hashed = rix.auth.password.hash("correct-password");

Hashing returns an explicit result.

Always check the result before using .value():

cpp
if (hashed.failed())
{
  const auto &error = hashed.error();
  return 1;
}

auto password_hash = hashed.value();

The returned value is the encoded password hash.

Store the hash, not the plain-text password.

Verify a password ​

Use:

cpp
bool valid = rix.auth.password.verify("correct-password", password_hash);

verify returns true when the plain-text password matches the stored hash.

Example:

cpp
const bool valid = rix.auth.password.verify("correct-password", hashed.value());
const bool invalid = rix.auth.password.verify("wrong-password", hashed.value());

The expected result is:

txt
valid   -> true
invalid -> false

Check password policy ​

Use:

cpp
bool accepted = rix.auth.password.accepts("correct-password");

This checks whether the password satisfies the configured password length policy.

Example:

cpp
const bool short_password = rix.auth.password.accepts("short");
const bool good_password = rix.auth.password.accepts("correct-password");

accepts does not hash the password.

It only checks whether the password is accepted by the password policy.

Use a custom configuration ​

Password hashing can use an Auth configuration.

Example:

cpp
auto config = rix.auth.config.development();

config.set_min_password_length(12);
config.set_max_password_length(1024);
config.set_password_hash_iterations(310000);
config.set_password_salt_size(16);
config.set_password_hash_size(32);

auto hashed = rix.auth.password.hash("correct-password", config);

Verify with the same configuration:

cpp
bool valid = rix.auth.password.verify("correct-password",hashed.value(), config);

You can also check the policy with the same config:

cpp
bool accepted = rix.auth.password.accepts("correct-password", config);

Create a password hasher ​

For repeated operations, create a hasher:

cpp
auto hasher = rix.auth.password.hasher();
auto hashed = hasher.hash("correct-password");

With custom configuration:

cpp
auto config = rix.auth.config.production();
auto hasher = rix.auth.password.hasher(config);
auto hashed = hasher.hash("correct-password");

The hasher exposes the configured policy:

cpp
hasher.min_password_length();
hasher.max_password_length();
hasher.iterations();
hasher.salt_size();
hasher.hash_size();

Development vs production configuration ​

Development configuration is easier to use in examples:

cpp
auto config = rix.auth.config.development();

Production configuration is stricter:

cpp
auto config = rix.auth.config.production();

For real applications, start with production configuration:

cpp
auto config = rix.auth.config.production();
auto auth = rix.auth.database(db, config);

Password settings are part of the Auth configuration because registration, login, and direct password hashing should follow the same policy.

Password policy failures ​

Hashing can fail when the password does not satisfy the policy.

Example:

cpp
auto hashed = rix.auth.password.hash("short");

if (hashed.failed())
{
  const auto &error = hashed.error();
  rix.debug.eprint(
      "auth error:",
      rix.auth.error.to_string(error),
      error.message()
  );

  return 1;
}

Common password hashing failures include:

txt
InvalidPassword
CryptoError

InvalidPassword means the password was rejected by the policy.

CryptoError means the underlying hashing operation failed.

Passwords during registration ​

When registering a user:

cpp
auto registered = auth.register_user({"ada@example.com", "correct-password"});

Rix Auth hashes the password internally before storing the user.

The user store receives a user with a password hash.

Application code should not store the plain-text password.

Passwords during login ​

When logging in:

cpp
auto login = auth.login({"ada@example.com", "correct-password"});

Rix Auth finds the user by email and verifies the plain-text password against the stored hash.

If verification fails, login fails with an authentication error.

A public application should usually return a generic message such as:

txt
Invalid email or password.

Do not reveal whether the email exists.

Security notes ​

Never store plain-text passwords.

Never log plain-text passwords.

Avoid logging password hashes in production.

Do not send password hashes to clients.

Treat password hashes as sensitive server-side data.

Use production configuration for real deployments.

Use database-backed auth when users must persist.

Complete example with custom policy ​

cpp
#include <rix.hpp>

int main()
{
  auto config = rix.auth.config.development();

  config.set_min_password_length(12);
  config.set_issuer("password-example");

  auto password = "correct-password";
  auto hashed = rix.auth.password.hash(password, config);

  if (hashed.failed())
  {
    const auto &error = hashed.error();
    rix.debug.eprint(
        "auth error:",
        rix.auth.error.to_string(error),
        error.message()
    );
    return 1;
  }

  const bool valid = rix.auth.password.verify(password,hashed.value(), config);

  if (!valid)
  {
    rix.debug.eprint("ERROR:", "password should be valid");
    return 1;
  }

  rix.debug.print("OK:", "password accepted and verified");

  return 0;
}

Run it:

bash
vix run password.cpp

What you should remember ​

Hash a password:

cpp
auto hashed = rix.auth.password.hash("correct-password");

Verify a password:

cpp
bool valid = rix.auth.password.verify("correct-password", hashed.value());

Check the policy:

cpp
bool accepted = rix.auth.password.accepts("correct-password");

Always check:

cpp
hashed.failed()

before using:

cpp
hashed.value()

Store password hashes.

Never store plain-text passwords.

Next step ​

Learn how sessions work.

Next: Sessions

Released under the MIT License.