Skip to content
Haven
← Notes from building HavenSAFETY

Why we create guardian links by hand

A link that grants access to a child's private messages is only as safe as the person holding it. The person most likely to ask a child for that link is exactly the person the protection exists to stop.

K
Keshav · · 4 min read

The obvious design is the dangerous one

A guardian needs access to their child's account. The obvious way to give it to them is a link: the student generates one, the guardian opens it, the relationship exists. One step, no waiting, no human in the loop. Most platforms do some version of this, and it is genuinely better than the alternative where a parent has no route at all.

It is also the design we refused, and the reason is the threat model rather than the convenience. A link that grants access the moment it is redeemed is exactly as safe as the person holding it. On a platform where the people being protected are children, the person most likely to persuade a child to hand over that link is the person the protection exists to stop.

That is not a hypothetical about strangers on the internet. It is the ordinary shape of coercion: someone the child already knows, asking for something that sounds administrative, from a child who has no reason to think a code is dangerous.

What we do instead

Haven splits the guardian relationship into two signals that have to arrive from two different places.

The student generates a single-use code that expires after twenty-four hours, and hands it to their guardian out of band — spoken, written down, however families actually communicate. The guardian redeems it on their own Haven account. That is the first signal, and it establishes one thing only: this child took an action naming this adult.

It grants nothing. The relationship is recorded with a status of claimed, and claimed is not access. A person at Haven then checks the relationship is real and records how they checked it, and only that second decision turns the link on.

Both halves are enforced in the database rather than in the interface. There is no client insert grant on the guardian table at all: the claim goes through a function that resolves the guardian from the authenticated session rather than accepting one as an argument, and the verification goes through a separate function that refuses any caller who is not staff.

The details that took the longest

Only the hash of a claim code is stored. The plaintext is returned once, at the moment it is created, and never written down — so reading the table hands nobody a working code, and neither does a leaked backup.

Generating a new code retires any earlier unconsumed one in the same statement. A student always has at most one live code, so a code shared a month ago and forgotten cannot be redeemed by somebody who kept it.

The alphabet omits the characters 0, O, 1 and I. A code that has to be read aloud or copied off a screen should not turn into a different code because two glyphs look alike.

Verification requires a method on record. A member of staff cannot mark a relationship verified without writing down how they satisfied themselves, because a verification with no reasoning attached is a boolean, and a boolean is not auditable.

Revoking a link stamps the moment consent ended, and the check that decides whether a guardian is verified reads both the status and that timestamp. Either one closes access on its own.

The thing we rejected that looked reasonable

An earlier shape let a guardian find their child by email address. It is the friendliest version of this flow, and it is the one we will not build.

On a platform used by children, a form that tells you whether an address has an account is an enumeration oracle. Type an address, learn whether that child is here. The feature that makes the flow pleasant for a parent is the same feature that makes it useful to someone who should not be looking.

The code exists precisely so the guardian never has to name the child. The student names themselves, by generating something and handing it over.

What this costs

It is slower. A guardian who expects a link to work immediately has to wait for a person, and the person is not always awake. We think that is the right trade, but we would rather say plainly that it is a trade than pretend the manual step is a feature.

It also does not scale by itself. Every verified guardian relationship on Haven has a human decision behind it, and that is a real constraint on how fast this part of the product can grow. When it stops being workable we will have to design something better — not remove the check.

What we will not do is make the code its own authorisation because the queue got long. The published version of this policy is on our Trust & Safety page, and the reason it is published is so that changing it has to be a visible act rather than a quiet one.

More from Haven

How the product works, and the safety decisions behind it.

Haven uses Google Analytics to understand which courses people find and where they get stuck. It sets a cookie and never receives your name, email or payment details. Declining keeps everything on the site working. Privacy Policy