The website that forgot you every three hours
Signing in to the cabinet meant a biometric face scan — and three hours later you had to do it again. The session length wasn't the bug; the missing half was renewal. Now the site quietly renews itself for fifteen days, and the hardest part was making sure it never renews twice at once.
Logging in to the personal cabinet isn't a password. It's MyID — you hold up your phone, scan your face, and the state's identity service vouches for you. It works, and it's genuinely secure.
It's also not something you want to do while checking whether your policy is still valid.
But that's what people were doing. Three hours after signing in, the site would forget them. Mid-session, mid-form, no warning: back to the home page, scan your face again. Some people were doing it several times a day.
The three hours weren't the mistake
The obvious fix is to make the session longer. That's the wrong instinct, and it's worth saying why.
A session token is a key. If someone copies it — a shared computer, a stolen laptop, a browser extension — they are you until it expires. A three-hour key limits that damage to an afternoon. A three-month key hands over your insurance account until autumn.
So the short life was correct. What was missing was the other half of the design: a way to renew without asking the person to prove who they are all over again. The mobile app already had a seven-day session. The website was the odd one out — short-lived tokens and nothing to renew them.
Two keys instead of one
The fix is a second token that does exactly one thing: prove you're allowed a new session token.
The short key is still short — three hours, sent with every request, and if it leaks it's stale by dinner. The renewal key lasts fifteen days, is never used to read your data, and is only ever spent on one endpoint.
When the short key expires, the site notices, quietly exchanges the renewal key for a fresh pair, and repeats the request that just failed. From the outside nothing happened. No redirect, no flicker, no face scan.
Two details behind that:
Each renewal key works once. Spend it and it's dead; you get a new one with the new session. If a stolen key is used before you use yours, the theft shows up as your session ending — which is far better than an attacker riding along beside you for two weeks.
The database never stores the key itself. It keeps a one-way fingerprint of it. Someone reading the table finds nothing they can log in with.
Four requests, one key
Here's the part that took the longest, and it isn't obvious.
Opening the cabinet fires several requests at once — your profile, your policies, your medical card, your claims. They all carry the same session key, so when it expires, they all fail at the same moment.
The naive version has each of them renew. The first one succeeds and burns the key. The other three try to spend a key that no longer exists, get refused, and log you out — immediately after a successful renewal. You'd see a random logout every few hours and never reproduce it on demand.
So the whole app now shares a single renewal in flight. The first failure starts it; the rest wait for that same answer and carry on with the new key. One renewal, four rescued requests.
The server takes the same problem seriously from the other side. Two tabs can still race. Marking a key as spent is done as a single conditional update — revoke this row, but only if it isn't already revoked. One tab wins, the other is told no. No locks, no timing window.
There's also a small, deliberate refusal: the server reads the session length from the stored key, not from whoever is asking. Otherwise a web session could ask for a mobile-length one.
The bug that only appears when two people use it at once
While wiring the renewal, I found a related fault that had been quietly breaking the header.
The site renders on the server before it reaches your browser. To avoid asking for the same profile twice, there was a "request already in progress" marker — stored as an ordinary variable in the file.
On your own laptop that's fine. On a server handling many visitors at once, that variable is shared by everyone. One visitor would end up waiting on a stranger's request, never receive their own, and render as logged out — while the cabinet itself worked, because it only needed the key. That was half of the long-standing "the header forgets I'm signed in" complaint.
The marker now lives per-visitor. Same idea, correct scope.
When it should still log you out
Renewal isn't forever, and pretending otherwise would be its own bug.
If the renewal key is genuinely gone — expired, revoked, already spent — the session ends properly: the keys are cleared, you land on the home page, and the MyID window opens. And a request is only ever retried once. If the second attempt fails too, that's a real logout, not a loop.
One last thing that only shows up outside the office: the session cookie was marked "HTTPS only",
which browsers quietly exempt for localhost. It worked on every developer's machine and failed on
the shared test server, where teammates could log in successfully and still be treated as guests.
The rule now checks whether the connection is actually encrypted rather than assuming.
Why I'm happy with it
The security didn't get weaker — the exposed key is still three hours, exactly as before. What changed is that the person no longer pays for that choice with their face, six times a day.