Designing a Secure “Reschedule Meeting” Workflow Without User Login
- Frederick Lewis
- Oct 21, 2025
- 4 min read
When designing user flows, there’s always a tradeoff between convenience and security. In this post, I walk through the design of a reschedule workflow for an app I developed that has a meeting feature. The workflow allows users to update their meeting time without logging in, while still keeping the system safe from abuse.
🧭 The Requirement
We wanted users to be able to reschedule meetings with a single click - no need to log in or navigate through a dashboard.
Goal: Allow users to reschedule their meeting easily without having to log in.
This meant sending users a reschedule link via email or calendar invite that takes them directly to a date/time picker for their meeting. But removing authentication means the link itself becomes the identity, so we need to protect it carefully.
⚠️ The Unsafe Option
The simplest version might look like sending the roomID in the url. Note this is sent as a base64 encoded value, but for simplicity here we will just refer to the room ID directly.
When clicked, the app fetches meeting details for roomId=12345 and allows rescheduling.
That’s easy to build, but dangerously insecure and open to the following attack vectors.
🔓 Attack Vectors
1. Tampering
A legitimate user receives a reschedule link but edits the URL manually:
If the backend trusts the input, they could now view and reschedule someone else’s meeting.
➡️ Result: Unauthorised modification of another user’s meeting.
2. Forgery
An attacker who never received a link could try to guess valid room IDs like 1, 2, 3, etc.If meeting IDs are predictable, they might stumble upon a valid one.
➡️ Result: Attacker can generate valid links and reschedule other user's meetings.
3. Enumeration Scanning
A more sophisticated attacker could automate this process:
for i in {1..10000}; do
curl https://ourapp.com/reschedule?roomId=$i
doneEven if the attacker can’t reschedule, if the endpoint leaks any metadata (like titles or times), this can expose meeting information at scale.
➡️ Result: Large-scale data leakage.
We can protect against these vectors with a few simple measures.
🛡️ Using Signed Tokens
To close off these attack vectors, we replaced the room ID with a signed token.This token contains the necessary information (like the room ID and expiry time) but is tamper-proof and unguessable.
When a room is booked:
A token is created containing:
{
"roomId": "12345"
}This data is then digitally signed using a server secret:
signature = HMAC(data, secret)The full token sent to the user is the roomId and the signature:
roomId=12345.signature
roomId=12345.c2lnbmF0dXJlIjoi...The reschedule link sent to users becomes:
https://ourapp.com/reschedule?token=roomId=12345.c2lnbmF0dXJlIWhen a user clicks the link to reschedule:
The token is sent to the backend for verification.
The backend:
Recomputes the signature using the room ID in the token and the secret stored in the server.
Compares it to the signature in the token, confirming that both the room ID hasn't been tampered with and that the signature was generated using the same secret (i.e. generated legitimately from the server)
If everything checks out, it fetches the relevant meeting details for the reschedule page.
🧩 Why This Immediately Protects Against Attacks
Changing the room ID invalidates the signature. The backend can detect this instantly when verifying. It's impossible to guess or construct a valid token without knowing the secret, and using a HMAC-SHA256 secret makes it computationally infeasible to guess the secret.
This setup already makes the system safe for most low-risk actions like meeting rescheduling.
At this stage, the system:
Doesn’t require user login.
Prevents tampering, forgery, and enumeration.
🧱 Adding More Protection: Token Expiry
Whilst the above provides a decent level of security, there is still the risk that tokens get leaked (e.g. a users email service gets hacked).
We can protect against this by adding a short-lived expiry date to the data in the token. When the token is received by the server, this expiry date is verified. Keeping the token short-lived reduces the attack window. I.e. If the token has 24 hour expiry, the attacker has only 24 hours in which they can take advantage of this (retrieve room details).
🧱 Adding More Protection: Token Storage
While signed tokens are secure on their own, there are some operational reasons to store them in the database:
Revocation: If the host cancels the meeting, we want to disable rescheduling immediately.
One-time use: We may want the reschedule link to stop working after it’s been used once, introducing an additional level of security.
Incident response: If a signing secret is compromised, we can revoke all tokens issued with that secret.
These benefits require a lookup table of valid tokens - which means storing them somewhere.
⚠️ New Risk: Database Leaks
Once we store tokens, we introduce a new risk: if the database is ever leaked, attackers could potentially reuse valid tokens to reschedule meetings.
This creates a fresh attack surface - but one we can mitigate.
🔒 Protecting Stored Tokens: Hashing
To prevent this, we never store the raw tokens.Instead, we hash them before saving, just like passwords.
Example:
hashedToken = SHA256(token)When verifying a token:
The backend hashes the provided token.
Compares it to the stored hash.
If they match, the token is valid and hasn’t been used before.
This way:
A leaked database reveals only hashed tokens, which can’t be used directly.
We still retain operational control (revocation, one-time use, etc.).
Attackers gain nothing from a data breach.
🧩 Conclusion
Designing user flows that balance convenience and security is always a tightrope walk. In this case, enabling users to reschedule meetings without logging in required treating the reschedule link itself as a form of authentication — and therefore securing it like one.
By moving from simple room IDs to signed, expiring tokens, and later to hashed token storage, we achieved a system that’s both frictionless for legitimate users and highly resistant to tampering, forgery, and large-scale abuse.
Ultimately, this workflow demonstrates a key design principle:
Convenience doesn’t have to come at the cost of security — if the link is the identity, then secure the link.