Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Web Security (OWASP Top 10:2025)  Module 8 – A07:2025 Authentication Failures

Sessions: IDs, fixation, timeouts and logout

Issue session IDs that cannot be guessed, replace them at sign-in, end sessions by time and by logout, and check each rule against a weak and a fixed store.

  • Intermediate
  • 30 minutes
  • Examples run with Node.js 24.21.0, quickjs 0.32.0, Python 3.14.8, Pyodide 314.0.7 and sql.js 1.14.2
  • By MySmartCoPilot
Free intro, Pro: 4 of 30 minutes free
Free: A session ID is a bearer secret, so the server must be able to end it. With a pass: the other 11 sections and 3 interview answers, about 26 minutes.

What you will learn

  • Choose between server-side sessions and signed cookie sessions by what each can end
  • Generate session IDs from a secure random source and replace them at sign-in and at re-authentication
  • Implement idle and absolute timeouts, a logout that deletes the record and sign out everywhere
  • Handle concurrent sessions, device lists, re-authentication for sensitive changes and a remember-me cookie
  • Log a fingerprint of a session ID instead of the ID, and keep IDs out of URLs

Before you start

What you’ll learn · Before you start

What you will learn

  • Choose between server-side sessions and signed cookie sessions by what each can end
  • Generate session IDs from a secure random source and replace them at sign-in and at re-authentication
  • Implement idle and absolute timeouts, a logout that deletes the record and sign out everywhere
  • Handle concurrent sessions, device lists, re-authentication for sensitive changes and a remember-me cookie
  • Log a fingerprint of a session ID instead of the ID, and keep IDs out of URLs

Before you start

On this page

Asha clicks Log out on a shared computer and walks away. In the first program below, a copy of her session ID, taken from a log line, still opens her account 145 minutes later, because the app cleared her cookie and left its own record of the session alone. The fixed app answers the same request with a 401.

A session is the server’s memory that a run of requests belongs to one signed-in person, and its ID is the key to that memory. The key can be trusted when it is random and long, when sign-in replaces it, when time and logout end it, and when ending it deletes the server’s record. Each rule comes with a check that fails on the weak store and passes on the fixed one.

A session ID is a bearer secret, so the server must be able to end it

After a person signs in, the server stores a record of who they are and gives the browser an ID that names the record. The browser sends the ID with every request, and the server believes whoever sends it. The ID is a bearer secret: A value that works for whoever presents it, with no proof that they are the one it was issued to. A session ID, an API key and an access token are bearer secrets: a copy is as good as the original., as good as the password for as long as the record exists. Step through one session, from the sign-in to a late copy of its ID:

Interactive · message by message One session, from sign-in to a late copy of its ID Step through a sign-in, a request and a logout, then watch what the server answers to a copy of the ID.
One session, from sign-in to a late copy of its ID, step 8 of 8. Messages so far: Browser to Your app: POST /login; Your app to Session table: ID and asha; Your app to Browser: Set-Cookie: sid; Browser to Your app: GET /account; Browser to Your app: POST /logout; Your app to Session table: delete the ID; Browser to Your app: GET /account (copy).Browserholds the IDYour appdecides every requestSession tableno record for the IDPOST /loginID and ashaSet-Cookie: sidGET /accountPOST /logoutdelete the IDGET /account (copy)

The drawing shows the whole scene; its 8 steps are listed below.

Every step as text
  1. Sign in. Asha sends her name and password. The app checks them first, and only a success makes a session.
  2. A record under an ID. The app writes a record to its table, "asha", under an ID of 128 random bits. The ID is a key to the record, and the record is the session.
  3. The browser keeps the key. The ID travels to the browser in a Set-Cookie header. From now on the browser sends it with every request to the site, so it is a bearer secret that anyone who holds it can use.
  4. Every request is a lookup. Each request carries the cookie. The app asks the table who the ID belongs to, and the table is the only thing that can answer.
  5. Logout. Asha clicks Log out. The browser tells the app, and the app has to end the session in the one place where it exists.
  6. The record is deleted. The app deletes the record from its table. Clearing the cookie in the browser is a courtesy to Asha. The deleted record is what ends the session.
  7. A copy of the ID arrives. Someone sends a copy of the ID, from a log line or another browser. The app asks the table, and there is no record under that ID.
  8. The answer. The table has nothing, so the app answers 401. The copy opens nothing, and so would a copy made yesterday. A server that did not delete the record would have answered 200.

The record in the table is the session, and four rules keep the table honest. Each has a part of this lesson to itself:

  • The ID cannot be guessed. It holds at least 128 bits from a secure random generator, as ASVS 5.0.0 requirement 7.2.3 asks.
  • Sign-in replaces the ID. A new ID at every sign-in means that an ID someone knew before it, a case of session fixation: An attack on a session whose ID someone knew before the person signed in. If the app keeps that ID after the sign-in, whoever knew it holds a signed-in session. MITRE files it as CWE-384., opens nothing.
  • Time ends the session. An idle limit and an absolute limit, both checked by the server against its own clock, end the sessions that nobody ended.
  • Logout deletes the record. A logout, a disabled account and a sign out everywhere all delete the record, because clearing a cookie ends nothing on the server.

The OWASP Top 10 names three of these failures in its category A07:2025: an ID reused after sign-in, an ID in the URL, and sessions that a logout or a period of inactivity does not end.

Where the record lives is a choice as well: in a table the server keeps, or inside a signed cookie that the server cannot take back. The program gives two small apps the same five requests. Both ask the browser to drop the cookie at logout, and only one deletes its record:

A copy of the ID, after logout, against two apps JavaScript · start/logout_replay.mjs
// Two small apps keep sessions in a table. Both clear the cookie at logout; only one deletes its record.
// A request is answered 200 when its session ID is in the table and 401 when it is not. Neither app has a timeout,
// so the minute only labels the step.

function makeApp({ deletesRecordAtLogout }) {
  const sessions = new Map(); // session ID -> user
  return {
    signIn(user, id) {
      sessions.set(id, user);
      return 200;
    },
    get(id) {
      return sessions.has(id) ? 200 : 401;
    },
    logout(id) {
      // Either way the response says "Set-Cookie: sid=; Max-Age=0", so the person's browser forgets the ID.
      if (deletesRecordAtLogout) sessions.delete(id);
      return 204;
    },
  };
}

const weak = makeApp({ deletesRecordAtLogout: false });
const fixed = makeApp({ deletesRecordAtLogout: true });

// A copy of Asha's ID, such as one that a proxy wrote to a log line. In a real app the ID is 128 random bits.
const ID = 'Zk3rV9mQ-demo-id';

const steps = [
  [0, 'sign in as asha', (app) => app.signIn('asha', ID)],
  [5, 'GET /account with the cookie', (app) => app.get(ID)],
  [10, 'Asha clicks Log out', (app) => app.logout(ID)],
  [20, 'GET /account with the copied ID', (app) => app.get(ID)],
  [155, 'GET /account with the copied ID', (app) => app.get(ID)],
];

console.log('minute  request                           weak app  fixed app');
for (const [minute, what, run] of steps) {
  console.log(`${String(minute).padStart(6)}  ${what.padEnd(32)}  ${String(run(weak)).padStart(8)}  ${String(run(fixed)).padStart(9)}`);
}

Output

minute  request                           weak app  fixed app
     0  sign in as asha                        200        200
     5  GET /account with the cookie           200        200
    10  Asha clicks Log out                    204        204
    20  GET /account with the copied ID        200        401
   155  GET /account with the copied ID        200        401

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node logout_replay.mjs

The weak app answered the copy with 200 at minute 20 and again at minute 155, which is 145 minutes after the logout, while the fixed app answered 401 both times. Neither app has a timeout, so the minute only labels the step: the weak app would have answered in the same way a year later.

Checkpoint

Check: A session ID is a bearer secret

  1. Question 1 of 2 An app answers a logout with 204 and "Set-Cookie: sid=; Max-Age=0", and never touches its table of sessions. What does a copy of the old ID do?
    Show the answer: Question 1 of 2

    Answer: It still opens the account, because the record is still in the table

    The weak app answered 200 to the copy at minute 20 and at minute 155. A session ends where it exists, in the server's table, so the logout has to delete the record.

  2. Question 2 of 2 Why is a session ID called a bearer secret?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: The server treats whoever sends it as the person it was issued to

    A bearer secret works for the one who bears it. That is why it must be unguessable, replaced at sign-in, limited in time and kept out of URLs and logs.

Flashcards · 4 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. Why is a session ID a bearer secret, and which four rules keep it trustworthy?

    The server believes whoever sends the ID, so it is as good as the password while the record exists. The ID cannot be guessed (ASVS 5.0.0 7.2.3: 128 bits or more, from a cryptographically secure generator); sign-in replaces it, so a known ID opens nothing (session fixation); time ends the session, with idle and absolute limits checked on the server's clock; and logout deletes the server's record.

  2. Why does clearing the cookie at logout not end a session?

    It ends nothing on the server. In the lesson a copy of Asha's session ID taken from a log line still opened her account 145 minutes after logout in the weak app, while the fixed app, which deleted its record, answered 401. A logout, a disabled account and a sign out everywhere all delete the record.

  3. Which three session failures does A07:2025 name?

    An ID reused after sign-in, an ID in the URL, and sessions that a logout or a period of inactivity does not end.

  4. Where can the session record live, and why did the logout test separate two apps?

    In a table the server keeps, or inside a signed cookie that the server cannot take back. Both apps asked the browser to drop the cookie at logout, and only the one that deleted its record could refuse the copy of the ID.

Guessing an ID is a numbers game, and 128 random bits win it Pro: opens with a Pro, Premium or Ultimate pass

In this part:

  • A new ID at every sign-in ends fixation, and only IDs the server issued are accepted
  • The server enforces an idle limit and an absolute limit, whatever the cookie says
  • Logout, a ban and a password change all delete records
  • A signed cookie cannot be taken back, so choose the design by what you must end
  • Devices, sensitive changes and remember-me each need a rule of their own
  • Keep session IDs out of URLs and logs
  • One request, checked in order
  • Practise: a session store you can trust
    • A session store with limits and a real logout
  • Interview questions
    • What is session fixation, and how do you prevent it?
    • An auditor signs in on a kiosk, clicks Log out, then replays the old session cookie from another machine and is still signed in. What is wrong, how do you fix it, and which test keeps it fixed?
    • Your app keeps sessions in signed cookies. Support needs "sign out everywhere" and "ban this user now", and the team will not add a lookup to every request. What can you offer, and what does each option cost?
    • A banking-style app and an internal wiki both need sessions. Choose idle and absolute limits, when to ask for a fresh sign-in, and whether to offer remember-me for each, and defend the difference.
  • Key takeaways

2 diagrams · 5 runnable examples (JavaScript (checks.mjs), JavaScript (fixed.mjs), JavaScript (weak.mjs), Python) · 1 exercise with sample tests · 3 interview answers · about 52 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Terms in this lesson

absolute timeout
The time from the sign-in after which the server ends a session however active it has been. No request restarts it, so it ends the sessions that are used for ever.
bearer secret
A value that works for whoever presents it, with no proof that they are the one it was issued to. A session ID, an API key and an access token are bearer secrets: a copy is as good as the original.
idle timeout
The time without a request after which the server ends a session. Each request restarts it, so it ends the sessions that someone left open.
session epoch
A number that the server keeps for each user and that a signed cookie carries. When the server raises its number, every cookie that carries an older one is refused.
session fixation
An attack on a session whose ID someone knew before the person signed in. If the app keeps that ID after the sign-in, whoever knew it holds a signed-in session. MITRE files it as CWE-384.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.