hash static method

Future<PasswordHashResult> hash({
  1. required String password,
  2. PasswordAlgorithm algorithm = PasswordAlgorithm.argon2id,
  3. int saltLength = SaltGenerator.minimumLength,
  4. AlgorithmConfig? config,
  5. String? pepper,
  6. PepperProvider? pepperProvider,
})
override

Hashes password and returns a PasswordHashResult.

Parameters

  • password: The plaintext password to hash. Must not be empty.
  • algorithm: Hashing algorithm. Defaults to PasswordAlgorithm.argon2id.
  • saltLength: Salt length in bytes. Must be ≥ 16. Defaults to 16.
  • config: Algorithm-specific configuration. Uses OWASP defaults if omitted.
  • pepper: A raw pepper string to mix in. Mutually exclusive with pepperProvider.
  • pepperProvider: A PepperProvider to fetch the pepper from.

Returns

A PasswordHashResult containing the self-contained encoded hash string. Only store PasswordHashResult.hash in your database.

Example

// Simple usage
final result = await PasswordGuard.hash(password: 'hunter2');

// With pepper from environment
final result = await PasswordGuard.hash(
  password: 'hunter2',
  pepperProvider: EnvPepperProvider(key: 'APP_PEPPER'),
);

// Custom config
final result = await PasswordGuard.hash(
  password: 'hunter2',
  config: Argon2Config(memory: 131072, iterations: 4),
);

Throws InvalidConfigurationException if config is invalid. Throws PepperException if pepper provider fails.

Implementation

static Future<PasswordHashResult> hash({
  required String password,
  PasswordAlgorithm algorithm = PasswordAlgorithm.argon2id,
  int saltLength = SaltGenerator.minimumLength,
  AlgorithmConfig? config,
  String? pepper,
  PepperProvider? pepperProvider,
}) async {
  if (password.isEmpty) {
    throw const InvalidConfigurationException('Password must not be empty.');
  }

  if (pepper != null && pepperProvider != null) {
    throw const InvalidConfigurationException(
      'Provide either "pepper" or "pepperProvider", not both.',
    );
  }

  final resolvedConfig = config ?? algorithm.defaultConfig;
  resolvedConfig.validate();

  final salt = SaltGenerator.generate(length: saltLength);

  // Resolve pepper
  final String? resolvedPepper;
  if (pepperProvider != null) {
    resolvedPepper = await pepperProvider.getPepper();
  } else {
    resolvedPepper = pepper;
  }

  // Apply pepper to password if provided
  final effectivePassword = resolvedPepper != null
      ? _applyPepper(password, resolvedPepper)
      : password;

  final hasher = _hashers[algorithm]!;
  final rawHash = await hasher.hashRaw(
    password: effectivePassword,
    salt: salt,
    config: resolvedConfig,
  );

  final encodedHash = HashParser.encode(
    algorithm: algorithm,
    config: resolvedConfig,
    salt: salt,
    hashValue: rawHash,
  );

  return PasswordHashResult(
    hash: encodedHash,
    salt: salt,
    algorithm: algorithm,
    createdAt: DateTime.now().toUtc(),
  );
}