← back to the section

You are checking the account area: under your own login no one else's orders are visible. You copy the address of an order page, open it in another browser as a different customer — and there is the same order in full, delivery address and phone number included. The interface is not at fault: the server handed the data over without asking whom it belongs to.

Findings like this live right behind the login form. To see them you need to know how the server recognised you, what it issued in return and what it rechecks afterwards.

the login hands out a pass — the server then judges by the header, not the screen POST /loginemail + passwordserverpassword checked200 OKaccess + refresh token GET /orders/17 + Bearer eyJ…200own order — served GET /orders/17 without header401never said who you are GET /orders/99 + other's token403not your order GET /orders/17 + expired token401exp in the past POST /refresh + refresh token200new pair, silently

The login trades a password for a token, and from then on the server judges every request by the header rather than by the screen: your own token opens your own order, a missing one gets 401, someone else's gets 403 on a resource that is not theirs, an expired one gets 401 again — after which the client silently swaps it using the refresh token. There is not a single button in this chain, which is why it cannot be tested with buttons.

The three words people mix up

«Authorization» is used for the login form and for access rights alike, and the defect then gets written up so vaguely that nobody knows what to fix. Let us separate the three steps on one shop customer.

Identification — you stated who you are: Anna types anna@example.com. That is not proof yet, only a claim; a username or a card number works the same way. Authentication — you proved it: Anna types her password, the server checks it and believes her. Proof can also be a code from a message or a fingerprint — two proofs of different kinds is what two-factor means. Authorization — what this person is allowed: Anna opens «All shop orders» and is refused, because she is a customer, not staff.

The answer tells them apart: 401 means «I do not know who you are» (no token, expired, tampered with), 403 means «I know, but you may not». You are recognised once, at the door, while rights are checked on every request.

What the login actually does

On screen the login is two fields and a button; in the exchange it is a single request: POST /login with the email and password in the body. The server checks the password (the database holds not the password but its irreversible fingerprint) and issues a pass: a cookie via Set-Cookie, or a token in the JSON body.

Watch this in the Network tab, opened before you press «Log in»: the status of /login, what came back, and how the client introduces itself on the next request — the browser attaches a cookie by itself, while the Authorization header is set by the page code.

Session or token: who remembers that you logged in

HTTP remembers nothing: every request arrives on its own, and a password typed a minute ago does not count towards it. The proof has to be carried along every time, and there are two ways to do that.

A session — the server keeps a record of its own: who logged in, when, until when. The client gets only its number, a random string in a cookie that the browser attaches to every request by itself. The contents stay on the server, which is why a session is killed instantly: delete the record and the number means nothing.

A token — the other way round: the server stores nothing and hands out a signed string that already says who this is; the client puts it into the Authorization: Bearer <token> header. Bearer means exactly that — whoever brings it counts as the owner. A token lives out its lifetime on its own and cannot be revoked as easily as a session, which is why logout is checked separately.

JWT: three parts separated by dots

The token in the response looks like eyJhbGciOi….eyJzdWIiOi….SflKxwRJf: two dots split it into three parts — how it is signed, what it claims, and the signature itself. The middle holds the user identifier, who issued the token, roles, and always exp, the moment after which the token is invalid, usually a handful of minutes away.

The key point: a signature is not encryption. The first two parts are not encrypted but re-encoded, and anyone can read them: paste a token from the Network tab into jwt.io and the contents show up in full. The signature protects against tampering: change the customer role to administrator and it stops matching, so the server answers 401.

Hence two checks: no personal data such as a phone or card number inside (the token ends up in logs and in browser storage), and editing the middle must end in a refusal rather than in extra rights.

The refresh token: why you are not thrown out every five minutes

If the short token were the only one, a person would type the password ten times an hour. So the login issues a pair: an access token good for minutes and a refresh token good for hours or days. Once access expires the client sends the refresh to the login server by itself and gets a fresh pair, and the user notices nothing.

A common finding lives here: «Log out» clears the browser storage but tells the server nothing, so a token copied before the logout still opens the account.

Sign in with Yandex: who trusts whom

The «Sign in with Yandex» button solves a separate problem: the shop must not learn your password for that account. Such an exchange is called OAuth — instead of the password the shop receives a token with limited rights.

The browser leaves for the provider's domain and the address bar changes, which is the key detail: a password is only ever typed where it belongs. The provider asks what the shop may have, then sends you back with a temporary code in the address; the shop exchanges that code for a token on its own. The Network tab shows the whole chain: a hop to another domain, the return with code, then ordinary requests carrying a token.

What to check

  • Someone else's resource by direct link. Open an order as Anna, then open the same address as Boris: the answer must be a refusal, not the data.
  • No token and someone else's token. The same request in Postman without the header — 401; with another customer's token — 403.
  • An expired token. Wait it out or have the lifetime shortened on the test stand: expect 401 and a silent refresh, not a bounce back to the login form.
  • Logout. A saved request with the old token stops working, the refresh too; «Back» must not show the account from the browser cache.
  • Password change and an old session. Log in from two browsers and change the password in one: whether the second session closes is a question for the requirements, and it has to be asked.
  • Hidden button, working request. The interface hides «Delete» from a customer — send the DELETE by hand: the server must refuse.
  • Sign-in with a provider. Declining on the consent screen leads to a readable page, not a blank one; password login and provider login with the same email land in one account.

Where people trip up

  • Checking through the interface only. No button means nothing was checked: holes are found by calling the address directly.
  • Testing on live accounts. Changing a real customer's password to see what a session does is an incident of its own; two test accounts with different rights are what you need.
  • Missing a token in the address bar. A ?token=… link ends up in browser history, in server logs and in a forwarded message — a defect even when everything works.
  • Treating 401 and 403 as the same thing. The wrong code in a bug report sends the fix the wrong way: recognition gets repaired instead of rights.

In short

  • Identification is stating who you are, authentication is proving it, authorization is what you are allowed; the first two happen at the door, the third on every request.
  • 401 means «I do not know who you are», 403 means «I know, but you may not»: different defects, repaired in different places.
  • A session lives on the server and dies instantly; a token lives on the client until its own expiry — hence the separate logout checks.
  • A JWT signature does not encrypt: anyone reads the middle, so no personal data belongs there, and editing it must produce 401.
  • After a logout both tokens must stop working, not only the one in the browser.
  • Rights are enforced on the server: a hidden button is not protection.