Security

    Password hashing for mobile app backends

    A 2026 view of a mobile app backend storing passwords as the output of a slow salted Argon2id hash, contrasted with the brute-forceable result of a fast general-purpose hash

    If your mobile app has user accounts with passwords, your backend stores those passwords, and how it stores them is one of the highest-stakes decisions in the whole system. Get it wrong, store them in plaintext, encrypt them reversibly, or hash them with a fast general-purpose hash, and a single database breach hands attackers your users' passwords, which they will reuse against your users everywhere. Get it right, with a slow, salted password hashing function, and even a full database leak leaves the passwords expensive to crack. This is server-side work, but it is core to your app's security. Here is how password hashing should work for a mobile app's backend.

    Short answer

    A mobile app's backend should store passwords using a dedicated, slow, salted password hashing function, never plaintext, reversible encryption, or a fast general-purpose hash. Per OWASP's Password Storage guidance, the recommended algorithm is Argon2id, with bcrypt, scrypt, or PBKDF2 as alternatives, each used with a per-user random salt and tuned cost parameters so hashing is deliberately expensive. Fast hashes like MD5 or SHA-256 are unsuitable for passwords because they can be brute-forced at enormous speed. The point is that even if your database is breached, properly hashed passwords are costly to crack. Hash on the server over TLS, do not treat a client-side hash as the password, and keep the algorithm and parameters current.

    What you should know

    • Never store plaintext or reversible passwords: a breach exposes them all.
    • Use a slow, salted password hash: deliberately expensive to compute.
    • Argon2id is recommended: with bcrypt, scrypt, or PBKDF2 as alternatives.
    • Fast hashes are unsuitable: MD5 or SHA-256 are brute-forced quickly.
    • Hash on the server: a client-side hash just becomes the password.

    Why does password hashing matter, and why not fast hashes?

    Because breaches happen, and the storage method decides what an attacker gets. If a database holding passwords is breached, and databases are breached, the question is what the attacker walks away with. Plaintext passwords are immediately usable, and reversibly encrypted passwords are nearly as bad, since the key is often nearby. Hashing is the right idea, storing a one-way transformation instead of the password, but the choice of hash is critical. General-purpose hash functions like MD5 or SHA-256 are designed to be fast, and that speed is exactly what makes them wrong for passwords: an attacker with a leaked database can compute billions of candidate hashes per second, cracking weak and common passwords almost instantly, especially without salting. Password hashing functions are instead deliberately slow and resource-intensive, so that each guess costs meaningful time and memory, which makes large-scale cracking expensive. Salting, a unique random value per password, prevents precomputed lookup tables and ensures identical passwords do not produce identical hashes. So the method matters because it determines whether a breach is a catastrophe or a contained, manageable event.

    How do you choose an algorithm?

    Use a current password hashing function with tuned parameters. The table summarizes the options.

    AlgorithmNotes
    Argon2idRecommended; memory-hard, tunable cost
    bcryptWell-established and widely supported
    scryptMemory-hard alternative
    PBKDF2Acceptable where a standards requirement applies
    Fast hashes (MD5, SHA-256)Unsuitable for passwords

    Argon2id is the generally recommended choice, a modern, memory-hard function whose cost in time, memory, and parallelism you tune so that hashing is expensive for an attacker but acceptable for a single legitimate login. bcrypt is a well-established and widely supported option that remains a sound choice. scrypt is another memory-hard alternative. PBKDF2 is acceptable, particularly where a standards or compliance requirement points to it, used with a high iteration count. What unites the appropriate choices is that they are purpose-built password hashing functions with a configurable work factor, used with a per-user random salt. Fast general-purpose hashes do not belong here at all, regardless of how they are combined, because their speed defeats the goal. Whichever you choose, set the cost parameters to current guidance and revisit them over time as hardware improves.

    How do you store passwords correctly?

    Hash on the server with a tuned, salted password function, and keep it current. When a user sets or changes a password, generate a unique random salt and hash the password with your chosen function, Argon2id or a sound alternative, using cost parameters tuned so a single hash takes a deliberate but tolerable amount of work, and store the hash and salt, not the password. On login, hash the submitted password the same way and compare. Always do this on the server, receiving the password over TLS, rather than hashing on the client and sending the hash, since a client-side hash simply becomes the de facto password an attacker could replay. Consider adding a pepper, a secret kept separate from the database, as defense-in-depth, so a database-only breach lacks part of what is needed. Plan to upgrade: as hardware gets faster, increase the cost parameters, and be ready to rehash to a stronger algorithm, for example on the user's next login. And combine strong hashing with the rest of your authentication posture, rate limiting, breach-password checks, and offering multi-factor or passkeys. The principle is that passwords are stored as the output of a slow, salted, current password hashing function computed on the server, so a breach does not hand over usable credentials.

    What to watch out for

    The first trap is using a fast general-purpose hash like MD5 or SHA-256 for passwords, or storing them in plaintext or reversibly, all of which make a breach catastrophic; use a slow salted password hash. The second is hashing on the client and treating that hash as the password, which just relocates the secret; hash on the server. The third is setting a password hash once and never revisiting the cost parameters as hardware improves. Password storage is server-side, so a pre-submission scan such as PTKD.com (https://ptkd.com), which reads the binary against OWASP MASVS, assesses the app's authentication handling and cryptographic usage, while the password hashing itself is implemented and enforced on your backend.

    What to take away

    • A mobile backend should store passwords with a slow, salted, dedicated password hashing function, never plaintext, reversible encryption, or a fast general-purpose hash.
    • Argon2id is recommended, with bcrypt, scrypt, or PBKDF2 as alternatives, each with a per-user random salt and tuned cost parameters, so a breach leaves passwords expensive to crack.
    • Hash on the server over TLS, do not treat a client-side hash as the password, consider a pepper, and raise cost parameters and rehash over time as hardware improves.
    • Password storage is server-side; use a pre-submission scan such as PTKD.com to assess your app's authentication and cryptographic handling, and implement hashing rigorously on the backend.
    • #password-hashing
    • #argon2
    • #bcrypt
    • #authentication
    • #backend
    • #owasp
    • #mobile

    Frequently asked questions

    How should a mobile app backend store passwords?
    As the output of a slow, salted, dedicated password hashing function, never as plaintext, reversibly encrypted, or with a fast general-purpose hash. When a user sets a password, generate a unique random salt, hash the password with a function like Argon2id using tuned cost parameters, and store the hash and salt rather than the password. On login, hash the submitted password the same way and compare. The goal is that even if the database is breached, the stored values are expensive to crack rather than immediately usable credentials.
    Why can't I use SHA-256 or MD5 for passwords?
    Because they are fast, and speed is exactly wrong for password storage. General-purpose hashes like MD5 or SHA-256 are designed to compute quickly, so an attacker with a leaked database can try billions of candidate passwords per second, cracking weak and common ones almost instantly, especially without salting. Password hashing functions are instead deliberately slow and resource-intensive, so each guess costs meaningful time and memory, making large-scale cracking expensive. The fast hashes do not belong in password storage regardless of how they are combined; use a purpose-built password hashing function.
    Which password hashing algorithm should I use?
    Argon2id is the generally recommended choice, a modern memory-hard function whose cost in time, memory, and parallelism you tune so hashing is expensive for an attacker but tolerable for a single legitimate login. bcrypt is a well-established, widely supported option that remains sound, scrypt is another memory-hard alternative, and PBKDF2 is acceptable where a standards or compliance requirement points to it, with a high iteration count. All are purpose-built password hashing functions with a configurable work factor, used with a per-user random salt. Set cost parameters to current guidance and revisit them over time.
    Should I hash passwords on the client or the server?
    On the server. Hashing should happen on the backend after the password is received over TLS, because if you hash on the client and send the hash, that hash simply becomes the de facto password, a value an attacker who obtains it could replay to authenticate. Client-side hashing relocates the secret rather than protecting it. So transmit the password over TLS and perform the slow, salted hashing on the server, storing the result. Client-side hashing can be an addition in specific designs, but it never replaces proper server-side password hashing.
    Do I need to update my password hashing over time?
    Yes. As hardware gets faster, the cost parameters that made hashing expensive become cheaper for attackers, so you should raise the work factor over time to keep cracking costly, and be ready to rehash to a stronger algorithm, for example transparently on the user's next successful login. Setting a password hash once and never revisiting it lets it age into weakness. Combine current hashing with the rest of your authentication posture, rate limiting, breach-password checks, and offering multi-factor or passkeys, for defense in depth.

    Keep reading

    Scan your app in minutes

    Upload an APK, AAB, or IPA. PTKD returns an OWASP-aligned report with copy-paste fixes.

    Try PTKD free