AnnouncementsIntroducing Arkoren

    Menu

    Hashing Overview

    Store password hashes and distinguish a successful password check from a mismatch or a storage failure.

    What's on this page
    1. Separate accepted-password rules from the work policy used to store passwords.
    2. Store complete salted records and distinguish successful checks, mismatches, and failures.
    3. Keep input encoding consistent and account for login timing and resource limits.
    On this page

    Password hashing lets you check a password without storing a readable copy. Arkoren’s hash.Hasher produces an encoded record containing the algorithm, work settings, random salt, and digest. Store that entire record; there is no decryption operation. A leaked record can still be attacked by guessing passwords.

    Unlike fast general-purpose hashes such as SHA-256, password-hashing algorithms deliberately spend time, and Argon2 also spends memory, on each guess.

    The examples assume a configured *hash.Hasher named hasher; choose and wire one on Drivers. Argon2id is the recommended choice for new passwords; bcrypt serves existing bcrypt databases and compatibility requirements. Focused fragments leave routine errors visible rather than showing application error propagation. Handle those errors before using their results.

    Password Policy

    Your password policy decides which new passwords the application accepts. The hash policy decides how much work storing and checking them costs. Hashing does not enforce minimum length, reject common passwords, or authorize a password change: even an empty value is valid input to the hashing contract.

    Validate new passwords before hashing, and apply request-size and password-byte limits before any expensive check. bcrypt requires a limit of 72 bytes on both creation and checking. Its native verifier can accept a longer attempt sharing a valid 72-byte prefix; never truncate the attempt. Argon2 has no such bcrypt-specific limit, but still needs bounded input and work.

    Do not apply a newly tightened minimum-length rule to existing login attempts; an older valid password might no longer satisfy your registration policy. Keep applicable resource limits and scheme-specific input limits on that path.

    Store Passwords

    At registration, hash only the validated password field, not the whole request. For example, your decoded registration input can have this shape:

    type RegistrationInput struct {
    	Email    string `json:"email"`
    	Password string `json:"password"`
    }

    With input already validated, create the stored record:

    stored, err := hasher.Hash(input.Password)

    On success, persist stored unchanged in the account’s password-hash column. Each call generates a fresh salt, so hashing the same password twice produces different records that both verify. You do not generate or store a separate salt.

    Use a column large enough for the chosen format and future policy changes. A text column avoids a fixed format-length assumption; if you choose a bounded column, test that complete records fit after changing salt or digest lengths. Never store or log the plaintext password alongside the record.

    Check Passwords

    At login, load the hash from application-owned account storage. Do not let a request supply the stored hash or its work settings: verification uses the record’s settings, not the current new-hash policy.

    Assume a decoded LoginInput with a Password string field, an account named account, and auth imported from arkoren.dev/core/http/auth. After enforcing the input limits above, check the attempt:

    matched, err := hasher.Check(input.Password, account.PasswordHash)
    if err != nil {
    	return err
    }
    if !matched {
    	return auth.ErrUnauthenticated
    }

    Only true, nil passes this credential check. A well-formed hash with a wrong password returns false, nil. An error matching errors.Is(err, hash.ErrInvalidHash) means malformed or unsupported stored data, not an ordinary mismatch. Import errors from the standard library and hash from arkoren.dev/core/service/hash when classifying it. Other encoding or driver errors are failures too; none authorizes login.

    Keep failures distinguishable internally without exposing storage details, passwords, or hashes to the client. The final digest comparison does not make the whole login request constant-time. Account lookup, unknown-account paths, different stored costs, and errors can change duration. Follow the account-hiding login flow for dummy checks and uniform public rejection; it is not a guarantee of identical request timing.

    Check does not update the account or consume the password. After success, check for a hash upgrade before discarding the attempt from your request handling.

    Input Encoding

    Exact string and []byte values use their raw bytes. Other values, including defined string or slice types, are JSON-encoded before hashing or checking. Use the same encoding on both paths; explicitly convert a defined password type to string if raw password bytes are intended. HashRaw and CheckRaw accept bytes directly.

    The typed methods clear their own encoded copy after use, not your input. The raw methods also leave the caller’s input unchanged. This is not a promise that all copies of a credential are erased from application memory.

    Slow password hashing is for guessable, human-chosen secrets. For securely generated, high-entropy API keys, a fast SHA-256 digest is appropriate instead. If you must recover a secret’s original value, such as an OAuth refresh token, use encryption, not password hashing.

    For all operations, see the hash API reference.

    Open a bulk documentation archive?

    This file contains every guide in its scope, not API declarations. Loading it all into an agent can exhaust its context window and increase processing time and cost. For coding tasks, start with the index and read only the relevant pages.

    Use the full archive for offline indexing, bulk processing, or deliberate large-context use.

    Browse the index instead
    Open archive