Email verification is often implemented as if it were a string-generation problem: create a random value, put it in a URL, and compare it later. That works for a demo, but production authentication needs a stronger model.
A verification token is a capability. Whoever presents it gets permission to perform one narrowly defined action. The backend should therefore control its scope, lifetime, audience, and consumption state. Treating the token as a capability makes replay behavior much easier to reason about, especially when a user clicks the link twice or an email client prefetches it.
This post describes a small REST API and PostgreSQL design that I use as a mental model for these flows. The important part is not the exact framework. It is the boundary between an unconsumed capability and the account change it authorizes.
A token is a capability, not just a string
Start with the action, not the token format.…