Flow
Where my supplier link stands
1What it proves
Signed with a server secret. Proves the server made it, not who holds it.
2What it can change
One order. Edits become the real order at once, price included.
3Where it gets written
Only in supplier emails and PDFs, after the list copy was removed.
4How it ends
No expiry yet, and no way to cancel a single link.
5Where it points
Settings first. If no public address is found, the link is left out.
Every row of my own order list got a working key from my first supplier edit link.
The ordering system emails each supplier a purchase order as a PDF, and now both the email and the PDF carry a link. It opens one order with no account, and the supplier can change quantities and prices, give a reason, and submit it.
A link that logs you in just because you have it is a credential, and credentials get copied: people forward mail, paste links into tickets, and servers keep logs. So I care about three things: what the link proves, what it can change, and where it gets written down. I got the last one wrong first.
Every row came with a key
My order list had a button on each order that opened the supplier's page. To make it work, the list made a fresh supplier link for every order, every time it loaded:
orders.map(o => ({ ...o, supplierToken: issueLink(o.id) }))
The list requires a login, so the people asking were fine. The problem was where the response ended up afterward, in caches, logs and browser developer tools, with each copy holding a non-expiring key to every order.
That came out the same day, and now a link is only generated when something is delivered to a supplier. Previously issued keys still work, though, because nothing rotated the secret, and rotating it is the only way to cancel links.
Three parts and a secret
The link holds a version, the order ID with the time it was made, and a signature made with a secret only my server knows. The server checks the signature before it trusts the order ID. After that it only uses that ID, never one the request sends. The supplier page and its API are the only new pages that skip login.
The signature proves my server made the link. It doesn't prove who's using it.
The supplier's numbers become the order
I thought of this as "they suggest, I approve." The code disagrees. A submit needs a reason, and it rejects bad lines and empty orders. Then it saves a new version, keeps the old one, makes new PDFs, and makes the new version the real order. Both copies get emailed. So the supplier's prices become the order right away, with nothing waiting for me to check.
One line per product, split back by store
The supplier page now shows one row per product, not one per store. When the supplier changes a total, it gets split back across stores by their old shares. That can wipe out a store's line by accident.
Finding an address a supplier can reach
The link needs a public web address. At first it could pick up an internal one, which would be a dead link. Now it tries settings first and the request last. If nothing works, it leaves the link out.
What the token doesn't check yet
Links don't expire. You can't cancel just one. The secret has a weak default. There are no tests yet.
The issue time is already sitting inside every token I've sent. I just never wrote the line that looks at it.