Skip to main content
auth.signin.start takes email_code, email_link or sms_code and returns a challengeId; auth.signin.verify takes that and the secret the person received. A code is six digits, lives ten minutes and allows five attempts. A link lives fifteen minutes. email_link also needs a redirectTo on an allowed redirect origin, because the link has to land somewhere. All three are on by default. Nothing about the answer reveals whether the address already has an account.

Passwords, which are off until you ask

password is the one method that starts switched off. Turn it on with auth.settings.set, then auth.password.set gives a user one and auth.password.signin uses it. The rules are the environment’s: at least twelve characters by default, and a breach check that asks a k-anonymity range service and fails closed when it cannot reach it. auth.password.remove takes a password off an account without touching the account.

Passkeys

auth.passkey.register.start and auth.passkey.register.verify add one; auth.passkey.signin.start and auth.passkey.signin.verify use it. auth.passkey.list and auth.passkey.remove are the user’s own management. A passkey binds to an origin, so in a live environment this method is unavailable until the environment has one: either a relying party id, or at least one allowed redirect origin to derive it from. A test environment always allows localhost origins, so passkeys work there on localhost with nothing configured. Change the relying party id later and every passkey already registered under the old one stops working.

Google, Microsoft and GitHub

auth.oauth.start returns where to send the person; auth.oauth.complete turns what comes back into a session. A provider works through a shared app registered by Lath when the deployment has one configured, and the consent screen then says Lath; where there is no shared app for a provider, that provider is unavailable until you register your own. auth.oauth.app.set sets your own client id and secret so the screen says your name; auth.oauth.app.list shows which is in use and the callback address to register, and auth.oauth.app.remove goes back to the shared one. Your own apps are set per environment — live and test each have their own.

Enabled is not the same as offered

auth.settings.get reports three things per method: whether it is enabled, whether it is available, and whether it is therefore offered — plus the reason when it is not. A method can be switched on and still not work: sms_code needs a carrier registration that is active and a phone number to send from, and a social provider needs an app registered for it. Leaving one enabled while it is unavailable is fine. It starts being offered the moment what it needs is in place, and until then the hosted sign-in page does not show it. Calling a method that is switched off is refused with method_disabled. Starting too many sign-ins is refused with rate_limited: five per address and thirty per IP address in ten minutes, and thirty magic-link completions per IP address in the same window. A code is limited by its own five attempts instead.
Last modified on September 23, 2026