Introduction
"Anyone who knows the URL can see it" might sound wide open. But with the right design, you can get safety on par with a password-based system.
This article covers the measures we took to protect the guest-only pages without passwords. Since these pages handle sensitive information like door codes, we designed them carefully.
Making a URL Nobody Can Guess
Use a Random String
The string in the URL — the token — is a random value that can't be predicted. We never use anything with a pattern to it, like a booking number or a sequential ID.
With a random value of sufficient length, brute-forcing your way to a valid one isn't realistically possible. And nobody is ever going to stumble onto someone else's page by chance.
Store a Transformed Value in the Database
This is the important part. The token we issue is never stored in the database itself. What we store is the result of putting that token through a one-way transformation.
If the database leaks, anyone can open every guest's page
Even in a leak, the URL can't be reconstructed from the stored value
When someone visits, we run the token from the URL through the same transformation and check whether it matches the stored value. It's the same thinking behind how passwords are stored.
The secret key used for the transformation is different from the one used for admin logins. If one leaks, the other is unaffected.
Keep the Last 4 Characters for Admin Identification
So operators can see which URL they issued from the admin screen, we separately store just the last four characters of the token. That alone can't reconstruct anything, but it's plenty for telling multiple issued URLs apart.
The complete URL is shown on screen exactly once, right after it's issued. Close that screen and it can never be displayed again. If it's needed, a new one gets issued.
Giving It a Validity Window
Set a Clear Start and End
Every token has a window during which it can be used. It starts the moment it's issued and ends at the close of checkout day.
Once the stay is over, the token automatically stops working, so nobody is left with an open view of the door codes indefinitely.
What Moves and What Doesn't When Dates Change
When an operator changes the dates on a booking, the validity window has to adjust too. The rule we were careful about here: the end date moves, but the start date never does.
The accident where a URL you already sent goes back to 'not available yet'
If you tie the start date to the check-in date, pushing a stay back means a URL the guest was already using reverts to "not available yet". Once a URL has started working, it must not stop working. We made that a firm principle.
Have a Way to Revoke
For cases where you suspect a URL has fallen into someone else's hands, there's a revoke function. From the admin screen, an operator can invalidate the old URL and issue a new one.
On the other hand, when a booking is cancelled in the reservation management system, we deliberately don't revoke it. We simply set the booking's status to cancelled.
The reason is that a cancellation might itself be undone. If we revoked the URL, reversing the cancellation wouldn't bring the same URL back, and we'd have to send the guest a new one. Since the system checks booking status first, the page appears unusable to the guest while the booking is cancelled — and works again if it's reinstated.
Checking at Every Entrance
Screens and APIs Go Through the Same Checks
Besides the portal's top page, there's the entry instructions page, the house rules page, the AI assistant's connection point, and the document delivery endpoint.
Every one of them independently verifies the token and checks the validity window. We didn't build it so that "you got past the top page, so everything beyond is fair game". Even if someone types a URL in directly, each entrance stops them.
Anything with an abnormal length is rejected before we even look at the database
Look for a token whose transformed value matches what's stored
If it's cancelled, reject at this point
Evaluate revoked, too early, and too late separately
Make Every Failure Look Identical
An invalid token, a revoked token, a token that never existed — we don't distinguish between them. They all return the same "not found" result.
If someone can tell that "this URL exists but has been revoked", you've just told them there was a period when it worked. It's a small detail, but the habit of giving nothing away matters.
The only cases we distinguish for the guest's benefit are "too early" and "too late". Even then, that screen shows no booking details and no access codes — just contact information.
Keep It Away from Search Engines and Caches
Every portal page carries instructions not to be indexed by search engines and not to be cached.
That's to prevent a situation where someone opens the page on a shared computer and the next person hits the back button and sees the contents.
Actions That Require Verifying Identity
For irreversible actions like cancellation, knowing the URL alone isn't enough to go through with it. We ask for the email address used at booking and only proceed if it matches.
For that comparison, we use a method whose processing time doesn't vary with the input. That prevents anyone inferring information from differences in response time.
We also limit how many times someone can attempt the cancellation process. Even when managing that limit, we use the transformed value rather than the token itself, so the raw token never lingers in the server's memory.
Wrapping Up
Three things anchored our password-free access control.
- Store the transformed value — even if the database leaks, the URL can't be reconstructed
- Never move the start date — a URL that has started working must never revert to unusable
- Verify at every entrance — getting past one screen is not permission for what comes after
From Booking to Post-Stay — Email Notification Design
How we designed the email notifications that deliver the portal URL.
Payment Security Against Price Tampering and Double Charges
How we applied the same thinking around payments.
Designing the Post-Booking Experience — a Guest-Only Portal
For the portal's overall design, see this hub article.