Back to KB
Difficulty
Intermediate
Read Time
8 min

Credentials in web applications: how to store them properly

By Codcompass Team··8 min read

Beyond the .env File: A Practical Architecture for Application Secrets

Current Situation Analysis

Credential exposure remains the single most frequent root cause of application breaches. Industry breach reports consistently show that compromised secrets account for the majority of successful intrusions, yet development teams continue to treat credentials as interchangeable data blobs. The fundamental misunderstanding lies in assuming that "security" means applying a single protective layer across all sensitive values. In reality, passwords, session tokens, and service keys operate under completely different threat models, lifecycle requirements, and cryptographic constraints.

This problem persists because modern frameworks abstract away authentication mechanics, leading developers to copy-paste patterns without understanding the underlying security properties. A session token stored in browser storage, a database password baked into a container image, and a user password encrypted with AES-256 all share one fatal flaw: they violate the principle of cryptographic separation. When an attacker gains read access to a database, a client-side script, or a build artifact, the damage scales directly with how poorly these categories were isolated.

The technical reality is unforgiving. Fast cryptographic hashes like SHA-256 can be computed billions of times per second on consumer GPUs, reducing password cracking to a trivial brute-force exercise. Client-side storage mechanisms like localStorage are directly accessible to any JavaScript execution context, making them trivial targets for cross-site scripting (XSS) payloads. Build-time secret injection leaves historical layers in container registries that can be extracted by anyone with pull access. Treating these distinct vectors with a uniform approach guarantees eventual compromise.

WOW Moment: Key Findings

The architectural divergence between credential types is not theoretical; it dictates your entire security posture. Misaligning storage, validation, and lifecycle management across these categories creates immediate attack surfaces.

Credential CategoryStorage MechanismRevocation ModelCryptographic Property
User PasswordsOne-way hash (Argon2id/bcrypt)Password reset flowMemory-hard, salted, irreversible
Session TokensServer-side store + HttpOnly cookieServer-side deletionHigh-entropy opaque string
Service SecretsRuntime injection / Secret ManagerImmediate rotationSymmetric/Asymmetric key material

This comparison reveals why a unified approach fails. Passwords require irreversible transformation to survive database leaks. Sessions require server-controlled state to enable instant revocation. Service secrets require runtime isolation to survive build pipeline or container exposure. When you force one category into another's storage pattern, you sacrifice either revocation capability, cryptographic safety, or deployment security. Recognizing these boundaries enables you to design systems that contain breaches rather than amplify them.

Core Solution

Building a resilient credential architecture requires separating concerns at the framework level, enforcing cryptographic boundaries, and injecting secrets at runtime. The implementation below demonstrates a TypeScript/Node.js backend that enforces these principles across all three categories.

1. User Passwords: Memory-Hard Hashing with Automatic Salting

Passwords must never be stored in recoverable form. The correct approach uses a memory-hard, key-derivation function that intentionally slows down ver

🎉 Mid-Year Sale — Unlock Full Article

Base plan from just $4.99/mo or $49/yr

Sign in to read the full article and unlock all 635+ tutorials.

Sign In / Register — Start Free Trial

7-day free trial · Cancel anytime · 30-day money-back