Most applications get the login flow working and stop there. The defects that matter appear afterwards, in how the resulting session is issued, stored, scoped and ended.

The state parameter is not optional

In an OAuth authorisation code flow, the state parameter binds the callback to the request that started it. Omitting or failing to validate it allows cross-site request forgery against the login flow, where an attacker causes a victim to complete a sign-in that links the attacker's account. Generate it randomly, store it server-side or in a signed cookie, and reject any callback whose state does not match.

Session fixation

If a session identifier is issued before authentication and kept afterwards, an attacker who plants a known identifier can use it once the victim signs in. Always issue a fresh session identifier at sign-in, and again on any privilege elevation.

  • HttpOnly, so scripts cannot read the session — this is what limits the damage of an XSS flaw.
  • Secure, so it is never transmitted over plain HTTP.
  • SameSite=Lax as a baseline, Strict where the flow allows it.
  • A specific path and host rather than a wildcard domain shared with untrusted subdomains.

Revocation

A self-contained signed token that the server cannot invalidate means a compromised session stays valid until it expires. If sessions must be revocable on password change, sign-out or compromise — and they must — keep server-side state, or use short-lived access tokens with a refresh token you can revoke. Decide this deliberately rather than discovering it during an incident.

Lifetime and visibility

  • Set an absolute maximum lifetime as well as an idle timeout.
  • Invalidate every other session when a password is changed.
  • Show users their active sessions with device and approximate location, and let them end one.
  • Log session creation with address and user agent — that log is what makes account takeover visible.