Application security guide

Authentication and session handling, and the flaws that still dominate

Almost nobody loses accounts to a broken hash function any more. They lose them to reused passwords tried in bulk, to a password reset flow with weaker controls than the login it bypasses, and to a second factor that a proxy in the middle can relay in real time. Those three account for most of what actually happens, and none of them is fixed by the work most teams do on this. The mechanism you choose matters more than the strength of anything you configure.

Which authentication flaws still dominate?

Credential stuffing, weak account recovery, and phishable second factors. Stuffing works because passwords are reused across services and lists of known pairs are abundant, so an attacker does not need to break anything: they authenticate correctly, with the user's own password, at a normal rate from many addresses. Recovery flows are next because they are a second, less scrutinised way to obtain a session, and they are frequently built once and never reviewed. Then relay phishing, which defeats one-time codes by asking the victim for them while the attacker uses them.

What does not dominate is the thing most effort goes into. Password composition rules, forced rotation and complex hashing configuration produce marginal gains at best, and composition rules make things worse by pushing users toward predictable substitutions. Current guidance from NIST, in the digital identity guidelines, moved away from mandatory complexity and periodic rotation years ago and toward length, screening against known breached passwords, and blocking anything at all if it appears on such a list.

The practical implication is a reordering. Screen new and changed passwords against a breached-credential list, rate limit by account rather than only by address, deploy an origin-bound second factor, and audit the reset flow. That sequence addresses what happens. Tightening the character requirements addresses what audits ask about.

How should passwords be stored and what should the policy be?

Use a purpose-built password hash with a tunable cost: Argon2id, scrypt, or bcrypt with a work factor you have actually measured on your hardware. The property that matters is deliberate slowness, so that an attacker holding your database gains far less per guess. A general-purpose fast hash, even a modern one, is the wrong primitive here regardless of how many rounds you apply by hand, and a salt is necessary but not sufficient.

For policy, set a generous minimum length, allow long passphrases including spaces and every character, do not truncate, and do not block pasting, because blocking paste actively discourages password manager use. Drop composition requirements. Drop scheduled expiry unless a specific regulatory obligation in your jurisdiction requires it, and if one does, say so in the policy rather than implying it is a security improvement.

The single highest-value addition is a breached-password check at the point of setting or changing one. Rejecting a password that already appears in public compromise data removes the exact input that credential stuffing relies on, and it can be implemented without sending the password anywhere by using a range-query approach over a hash prefix.

Which second factor is actually worth deploying?

They differ in what they resist, and the distinction that matters is whether the factor is bound to the origin it is being used on. A code a human can read out can be relayed by an attacker; a signature over the domain cannot.

FactorStops bulk credential stuffingStops real-time phishingMain failure modeRecovery risk
Password onlyNoNoReuse across servicesReset flow is the whole perimeter
One-time code by SMSMostly yesNoNumber porting and interceptionCarrier support desk becomes an attack path
Authenticator app codeYesNoUser reads the code to a proxy siteBackup codes stored insecurely
Push approval promptYesOnly with number matchingApproval fatigue from repeated promptsDevice rebinding with weak checks
Passkey or security keyYesYes, the signature is origin-boundLost device with no second credential registeredFallback to a weaker factor undoes the benefit
Federated sign-in to an identity providerYes, if the provider enforces itDepends entirely on the providerProvider outage or account compromise cascadesEmail-based account linking

How should sessions and tokens be handled?

Regenerate the session identifier at every change in privilege: at sign-in, at step-up authentication, and at role change. This single step removes session fixation, where an attacker plants a known identifier before login and inherits the authenticated session afterwards. Then set the cookie correctly: HttpOnly so scripts cannot read it, Secure so it never travels in clear, and an explicit SameSite value chosen deliberately rather than inherited from a browser default that may change.

Keep revocation on the server. The attraction of a self-contained signed token is that no lookup is needed, and the cost is that you cannot invalidate it before it expires, which means sign-out, a password change, or a detected compromise do not actually end the session. If you use signed tokens, keep the access token lifetime short, rotate refresh tokens on every use, detect reuse of an already-rotated refresh token as a compromise signal, and hold a revocation list for the cases that matter.

Validate tokens strictly. Check the signing algorithm against an expected value rather than trusting the header, check the issuer and the audience, and check expiry with limited clock tolerance. Algorithm confusion and unvalidated audience remain common findings precisely because a library will happily verify a signature and tell you nothing about who the token was meant for. For federated flows, use the authorisation code flow with PKCE, verify the state parameter, and match redirect URIs exactly rather than by prefix.

Why is account recovery the real perimeter?

Because it is an alternative route to an authenticated session, and it is almost always guarded more weakly than the front door. A system with strong passkeys and a reset link sent to an email address protected by a password has the security of the email account, not of the passkey. Attackers know this, which is why account takeover work concentrates on recovery rather than on login.

Get the token mechanics right: unpredictable and generated with a cryptographic source, single use, short expiry, bound to the account, invalidated when a new one is issued, and never placed anywhere it can leak through a referrer header or a log. Do not reveal whether an address is registered, and keep the response and the timing identical either way. Require the current session or the second factor before allowing an email address or a factor to be changed, because changing the recovery address is the step that makes a takeover permanent.

Then close the loop after a successful reset. Invalidate every existing session, notify the account holder on a channel they control, and record the event in an audit trail an attacker cannot edit. A reset that leaves the attacker's old sessions live, or that succeeds silently, converts a recoverable incident into an unnoticed one.

What can you test this week?

Four tests, each under an hour. Log in, capture the session identifier before and after authentication, and confirm it changed. Request a password reset, use the link, then check whether a session established before the reset still works. Submit the same login endpoint fifty times for one account from different addresses and see whether anything throttles by account rather than by address. Then take a valid token and modify the audience claim, and see whether your service still accepts it.

Add one enumeration check while you are there. Compare the response body, status code and response time of a login or reset attempt for a registered address against an unregistered one. Differences in any of the three give an attacker a list of valid accounts, which is the input to everything above.

If any of the four fails, the fix is small and local, which is the useful characteristic of this whole area: the flaws that dominate are configuration and sequencing errors rather than architectural ones. That is also why they persist, because nothing in a normal test suite notices them and no scanner reliably reports them.

Common questions

What is the most common authentication vulnerability?
Credential stuffing, where an attacker submits username and password pairs from other services' breaches. It requires breaking nothing, because the credentials are correct, which is why rate limiting by account rather than only by source address matters. The other two dominant failures are weak account recovery flows, which offer a second route to a session, and second factors that a proxy can relay in real time.
Should users be forced to change passwords regularly?
Generally no. Current NIST digital identity guidance moved away from mandatory periodic rotation and from composition rules, because both push users toward predictable patterns. Length, allowing passphrases, permitting paste so password managers work, and screening against known breached passwords deliver more. If a regulatory obligation in your jurisdiction requires expiry, state that as the reason rather than implying a security benefit.
Which multi-factor method resists phishing?
Only origin-bound credentials, meaning passkeys and security keys built on the web authentication standard. The signature they produce is tied to the domain requesting it, so a proxy site cannot relay it. Codes from SMS or an authenticator app can be read out by a victim to an attacker in real time. Push approvals help only with number matching, and any fallback to a weaker factor reinstates the original risk.
How should session cookies be configured?
HttpOnly so scripts cannot read them, Secure so they never travel unencrypted, and an explicit SameSite value chosen deliberately rather than left to a browser default. Regenerate the session identifier at sign-in and at any privilege change, which removes session fixation. Set an idle timeout and an absolute maximum lifetime, and ensure sign-out invalidates the session on the server rather than only deleting the cookie.
What are the common mistakes with signed tokens?
Trusting the algorithm named in the token header instead of checking it against an expected value, not validating the issuer and audience, allowing long lifetimes with no revocation path, and storing tokens where scripts can read them. A library will verify a signature and tell you nothing about who the token was intended for, so audience validation has to be explicit. Rotate refresh tokens and treat reuse as a compromise signal.
How do you secure a password reset flow?
Generate the token from a cryptographic source, make it single use with a short expiry, bind it to the account, and invalidate earlier tokens when a new one is issued. Keep responses and response times identical for registered and unregistered addresses. Require the current session or a second factor before an email address or a factor can be changed, and after a successful reset invalidate all existing sessions and notify the account holder.

More on Application security

Let’s create something out of this world together.

Have a project in mind? Contact us for expert design and development solutions. Let’s discuss how we can help grow your business.

Azaadi Offer

Claim a free security assessment

Until 31 August we're covering the cost of a full vulnerability assessment and penetration test. Mention it in your message and we'll scope it with you.

  • Web application testing, authenticated and unauthenticated
  • Mobile application testing across iOS and Android
  • External network and infrastructure assessment
  • Manual exploitation by engineers, not scanner output

Testing and the report are free. Fixing what we find is quoted separately, with no obligation to accept.

Read the full offer

Tell us what you are trying to build and we will tell you plainly whether we are the right people for it. Book a call with an expert to work through the detail, or ask for a fixed quote if the scope is already clear. No obligation either way.

Four fields is all we need to get started.

Fastnexa Logo

© 2026 fastnexa. All rights reserved.