2.2 · Sessions, cookies & simple authentication

Level 2 · PHP & the Web

2.2Sessions, cookies & simple authentication

Goal: Keep state across pages (server-side sessions, cookies) and build simple but SAFE authentication (hashed passwords, protected session) — the basis of user accounts.
Estimated time: 11 min · self-paced reading · If you only have 5 min: read “The essentials in 30s” + the diagram.

The essentials in 30 seconds

  • HTTP forgets everything: each request stands alone — cookies and sessions add “memory” across pages (who is logged in, cart, preferences).
  • Sessions for sensitive data, cookies for preferences: trusted data on the SERVER ($_SESSION, not modifiable) — never put sensitive data in a modifiable cookie.
  • Hashed passwords, never in plain text: password_hash at registration, password_verify at login, regenerated session ID — no exception.

Running mini-case — Riad keeps his members logged in

Riad builds on his form (2.1): the association's members must stay logged in from page to page to see their personal area. Since HTTP is stateless, he adds memory: a cookie for the language preference (not sensitive), a session for the identity (sensitive, server side). At login he checks the password with password_verify against a hash, regenerates the session ID, stores the identifier in $_SESSION; each protected page checks the session. In 2.3, he will factor the check into a file included everywhere; in 2.4, he will date the last login.

Sequel to thread 2.1: Riad's form becomes a member area with memory — and continues in 2.3 and 2.4.

1. Giving HTTP a memory: cookies and sessions

The HTTP protocol is stateless: each request is INDEPENDENT, the server “remembers” nothing between two pages. To remember state (who is logged in, a cart, preferences), two mechanisms. Cookies: small data items stored in the BROWSER, sent back to the server with each request — created with setcookie(), read in $_COOKIE. Client side, so VISIBLE and MODIFIABLE by the user: reserved for non-sensitive data (language, theme), with security options (HttpOnly against theft via XSS, Secure for HTTPS only, SameSite against CSRF). Sessions: the state is stored on the SERVER (the user cannot modify it); the browser only keeps a session identifier. In PHP: session_start() at the very top of the script (before any output), then storage and reading via $_SESSION ($_SESSION['user_id'] = 42;). Sensitive data lives in the session — never in plain text in a cookie. Riad applies this: language in a cookie, identity in a session.

2. Simple but safe authentication

Sessions are used notably for authentication. The cycle: at LOGIN, check the identifier and the password, then store the identity in the session ($_SESSION['user_id']); on each PROTECTED page, check the session (otherwise redirect to login); at LOGOUT, destroy the session (session_destroy()). Three protections are non-negotiable. First, passwords are stored HASHED with password_hash() and checked with password_verify() — never in plain text, never with a weak hash: a database leak would otherwise expose every account. Next, regenerate the identifier at login (session_regenerate_id()) against session fixation, with secure session cookies and HTTPS. Finally, control ACCESS: check not only that the user is logged in (authentication), but that they have the RIGHT to access the resource (authorization) — otherwise one member reads another's data by changing an id in the URL.

3. The traps that compromise accounts

Authentication is a high-stakes area: one mistake compromises real accounts. Traps to ban: storing a password in plain text; forgetting to regenerate the session ID; leaving session cookies without HttpOnly/Secure/SameSite; working without HTTPS; checking login but not authorization; revealing through over-precise error messages which emails exist; not limiting attempts (brute force); building queries by concatenation instead of prepared statements (SQL injection, level 3). Riad ticked off each point before opening the member area. And in a REAL PROJECT, prefer the PROVEN authentication systems of frameworks, which handle these subtleties correctly: understanding the mechanisms (as here) is essential, implementing them rigorously is even more so.

Common misinterpretation: “Storing the identifier in a cookie is the same as a session — and simpler.” No. A cookie lives in the browser: the user sees it, edits it, forges it — putting “user_id = 1” or a role there lets anyone claim any identity. The session keeps the data on the server, out of reach: the browser only holds an opaque identifier. Riad's rule is categorical: anything trusted (identity, role, cart) lives in $_SESSION; the cookie carries only non-critical preferences, secured with HttpOnly, Secure and SameSite.
Cookies vs sessions Client vs server CookiesClient-side data (modifiable) — preferences+SessionsServer-side data (safe) — identity, cart+SecurityHashing, regenerated ID, HTTPS, authorization Sessions for sensitive state; cookies for non-critical preferences.
Client vs server
Text version of the diagram (SEO / screen readers / translation): 1) HTTP is STATELESS: Riad must add memory to keep his members logged in. 2) COOKIES store preferences on the client (language) — modifiable, so never sensitive data, with HttpOnly, Secure, SameSite. 3) SESSIONS store identity on the server via session_start then $_SESSION — the browser keeps only an identifier. 4) SECURITY locks it all down: hashed passwords (password_hash/verify), regenerated ID at login, HTTPS, and authorization checked on each page. Lesson: sensitive = server, preferences = cookie.

🔎 Concrete example — 🔎 Concrete example — Riad's member login

Session + hashed password, as with Riad:

session_start();
if (password_verify($_POST['mdp'] ?? '', $user['hash'])) {
  session_regenerate_id(true);
  $_SESSION['user_id'] = (int) $user['id'];
}
// protected page:
// if (!isset($_SESSION['user_id'])) { header('Location: connexion.php'); exit; }

Reading: checked against the hash, regenerated ID against fixation, identity on the server.

Lesson: also check authorization (the RIGHT of access), not just login.

Section vocabulary

Stateless HTTP
Each HTTP request stands alone; the server does not remember previous ones; cookies and sessions add memory across pages.

Simple example: Riad must add memory to keep his members logged in.

What it is not: a server that spontaneously recognizes its visitors.

Reflex: state across pages = plan a cookie or a session.

Cookies ($_COOKIE)
Small data items stored in the BROWSER, sent back with each request (setcookie / $_COOKIE); client side so modifiable — HttpOnly, Secure, SameSite options.

Simple example: Riad remembers the chosen language in a cookie.

What it is not: safe storage for an identity or a role.

Reflex: cookie = non-sensitive preferences only.

Sessions ($_SESSION)
State stored on the SERVER, not modifiable by the user, the browser keeping only an identifier; session_start() then $_SESSION — the secure mechanism.

Simple example: Riad's members' identity lives in $_SESSION['user_id'].

What it is not: data the user can edit in their browser.

Reflex: trusted data = session.

Session authentication
Login: check identifier + password then store the identity in the session; protected pages: check the session; logout: destroy the session.

Simple example: Riad protects the member area with isset($_SESSION['user_id']).

What it is not: a page that trusts a modifiable cookie.

Reflex: each sensitive page = session check.

Session security
HASHED passwords (password_hash/verify, never in plain text), regenerated ID at login, secure cookies, HTTPS, and access control.

Simple example: Riad hashes at registration and checks with password_verify.

What it is not: a password stored in plain text or md5.

Reflex: new authentication = full security checklist.

In practice — In practice — Handling state and simple authentication

  1. Start a session (session_start() at the top of the script, before any output) and store/read data via $_SESSION.
  2. Create a cookie with setcookie() (HttpOnly/Secure options) and read it via $_COOKIE; understand that it is stored on the client (modifiable).
  3. Build authentication: at login, check the password (password_verify against a hash), store $_SESSION['user_id'], regenerate the session ID.
  4. Protect the pages (check the session, redirect otherwise) and handle logout (session_destroy); remember: HASHED passwords, protected session, HTTPS.
You keep state across pages (server-side sessions, cookies) and build simple but SAFE authentication (hashed passwords, protected session) — the basis of user accounts.

Ready-to-say script — justifying the session to the association manager (30 s)

“For the member area, the identity lives in the session, on the server: members cannot modify it. The cookie carries only the language. Passwords are hashed, never in plain text, and I regenerate the identifier at each login. If someone forges their cookie, they gain no access.”

Say it while showing a modified cookie that grants no access; the demo convinces.

Copy-paste template — login and protected page

' . htmlspecialchars('Invalid credentials.', ENT_QUOTES, 'UTF-8') . '

'; // --- protected page (espace.php) --- // session_start(); // if (!isset($_SESSION['user_id'])) { header('Location: connexion.php'); exit; } // --- logout --- // $_SESSION = []; session_destroy();

Language preference

Riad remembers French or Arabic in a long-lived cookie: not sensitive, perfect for the client.

Sensitive cart

The association shop's cart contents live in the session: members cannot change the prices.

Clean logout

One click empties $_SESSION and destroys the session: on a shared computer, no successor recovers the account.

Towards the framework

In a real project, Riad will entrust authentication to the framework's proven system — same principles, subtleties handled.

Caution: NEVER store a password in plain text (nor with a weak hash): a database leak would expose every account, with serious consequences for real people. Use password_hash at registration and password_verify at login, with no exception. This guide sets out the basic actions — have any real authentication reviewed by an experienced developer before going live.

✓ Best practices

  • Use SESSIONS for sensitive state (identity, cart).
  • Hash passwords with password_hash / password_verify, never in plain text.
  • Regenerate the session ID at login + secure cookies + HTTPS.

✗ Common pitfalls

  • Storing trusted data in a cookie (modifiable by the user).
  • Storing a password in plain text or with md5/sha1.
  • Checking only login and forgetting authorization (access to other people's data).

Key takeaways

  • HTTP is STATELESS (each request stands alone); COOKIES (browser side, $_COOKIE) and SESSIONS (server side, $_SESSION) add “memory” across pages.
  • SESSIONS = the SECURE mechanism: data on the server (not modifiable), the browser keeps only an IDENTIFIER. Cookies = client side (modifiable, for non-sensitive data).
  • AUTHENTICATION: login (check password, store identity in session) → protected pages (check the session) → logout (destroy).
  • SECURITY (high stakes): HASHED passwords (password_hash/verify, NEVER in plain text), regenerate the ID at login, secure cookies (HttpOnly/Secure/SameSite), HTTPS, access control (authorization).

48h challenge — apply it tomorrow

Build a minimal login: a hash created with password_hash, check with password_verify, session_regenerate_id, storing the identity in the session, a protected page that redirects otherwise, and a logout. Then forge your cookie and confirm that access stays denied.

Section exit checklist
  • I can explain the cookie/session difference and say where each data item lives.
  • I can build a login with hash, regenerated session and protected page.
  • I have checked that a forged cookie grants no access.
Self-rating 1-5: do I put each data item on the right side (server vs client)?do I refuse any plain-text password?

Frequently asked questions

Cookies or sessions: what is the difference, and which one for what?

Both give HTTP some “memory”, but differently. COOKIES: data in the BROWSER (client side), sent back with each request — VISIBLE and MODIFIABLE by the user, small size, possible long persistence; never sensitive data in plain text (HttpOnly, Secure, SameSite options). SESSIONS: data on the SERVER, the browser keeping only an IDENTIFIER; the user CANNOT modify the data; larger capacity; usually lasts for the visit. Sessions use a cookie (for the identifier) but the DATA stays on the server — that is the key difference. Use SESSIONS for SENSITIVE state (authentication, cart) — the default choice; COOKIES for NON-sensitive preferences and long persistence (language, theme). Secure both (cookie options, identifier regeneration, HTTPS).

How do I build correct authentication, and which traps should I avoid?

Steps: (1) REGISTRATION — validate, HASH with password_hash(), store the HASH (never the plain text). (2) LOGIN — fetch the user by email (PREPARED query), check with password_verify(), then session_regenerate_id() and store the identity in the session. (3) PROTECTED PAGES — check the session (isset($_SESSION['user_id'])), otherwise redirect. (4) AUTHORIZATION — check the RIGHT to THIS resource, not just login. (5) LOGOUT — empty then destroy the session. Serious traps: passwords in PLAIN TEXT or badly hashed (the worst), non-regenerated ID (fixation), insecure cookies, no HTTPS, forgotten authorization, error messages revealing emails, unlimited attempts (brute force), concatenated queries (SQL injection). In a REAL PROJECT, prefer the PROVEN authentication systems of frameworks.

Check your understanding

Where is SESSION data stored?

Additional resources (optional, to go further)

Level 2 examFresh, harder questions to test what you've learned