20 things AI leaves out of the login it built you
The gaps AI leaves in auth, from email verification to password reset and sessions, each with a copy-ready prompt and a browser check that proves it works.
Your login works. You tested it with a test account.
A test account never forgets its password, never changes phone, and never comes back a month later. Real users do all three, which is why the login an AI wrote in ten minutes holds up in your hands and falls apart in theirs. It built the happy path. Sign up, log in, done. Everything around that path is missing.
Below are twenty things it leaves out, in the order a real user meets them, each with a copy-ready prompt and a Verify line you run in a browser with no code to read. Then two more that decide whether any of it actually works.
One honest warning before you start. Twenty prompts take about fifteen minutes. The job does not. Four of these can log out every user you have, including you, the moment the prompt runs. Two are not finished when the AI says done, because the last step lives in a DNS panel rather than a chat. One of them, written the obvious way, hands any stranger a button that locks your users out of their own accounts. And nine cannot be checked without a second email address and a second browser, which is exactly why they were never tested the first time.
The twenty, as a checklist
Get in
- ☐ 1. Verify the email before first login
- ☐ 2. Resend the verification link
- ☐ 3. Expire verification links in 24 hours
- ☐ 4. Say “wrong email or password”, never which one
- ☐ 5. Rate limit login attempts
- ☐ 6. Lock after repeated failures, and unlock by email
Stay in
- ☐ 7. Keep users signed in for 30 days
- ☐ 8. Refresh sessions silently
- ☐ 9. Store sessions in httpOnly cookies, not local storage
- ☐ 10. Send expired sessions back to the page they were on
- ☐ 11. Add “log out everywhere”
- ☐ 12. Show active devices
Get back in
- ☐ 13. Reset password by email
- ☐ 14. Expire reset links in 15 minutes
- ☐ 15. Make reset links single use
- ☐ 16. End every session after a password change
- ☐ 17. Confirm email changes from the old address
- ☐ 18. Never reveal whether an email is registered
The account is theirs
- ☐ 19. Email the user on every password or email change
- ☐ 20. Let users delete their account
Logging in is easy. Getting back in is the product.
Ten minutes before you run anything
Do this on your live app, with no code, so you do not spend fifteen minutes adding things you already have.
You need three things first, and you will need them again for almost every check in this
article. A spare email address you can actually open, such as a second mailbox or a
+test alias, since you+test1@example.com lands in your own inbox and reads as a
different address to most apps. A private browsing window, so you can be two different
people at once. And your phone, on mobile data rather than your wifi, for the rate-limit
check.
| Do this | If this happens, it is missing |
|---|---|
| Sign up with a spare address. Do not open the inbox. Go straight to login | You get in without ever opening the mail (1) |
| On the “check your email” screen, look for a resend button | There is not one (2) |
| At login, try an address that never signed up, then your real address with a wrong password | The two messages differ (4) |
| Type the wrong password fifteen times, fast | The fifteenth behaves exactly like the first (5, 6) |
| Sign in, then open the browser’s storage panel and look for anything called token, jwt, access or session | A long string is sitting there (9) |
| Sign in, close the browser completely, reopen it, return to the app | You get the login screen (7) |
| Copy the URL of a deep page, log out, paste it back, log in | You land on the home page, not that page (10) |
| In settings, look for “log out of all devices” and a list of signed-in places | Neither exists (11, 12) |
| Use “forgot password” with your real address, and start a timer | Nothing in three minutes, or it lands in spam (13) |
| If a mail did arrive, use the link, then press Back and use the same link again | It works a second time (15) |
| Use “forgot password” with an address that has no account | It says no account was found (18) |
| Sign in as the same user in a private window, change your password in the first, then refresh | You are still signed in there (16) |
| Change your account email in settings and watch the old inbox | Nothing arrives at the old address (17, 19) |
| In settings, look for “delete my account” | It is not there (20) |
Under five misses and you are in better shape than most, so go straight to those items. Ten or more is normal for a login written in one sitting. Three items never show up in this test, numbers 3, 8 and 14, because they are about time passing, so they have their own checks below.
The order to run them in, and four warnings
The list is numbered in the order a user meets these. That is not the order to run them in. Work in three waves instead.
Wave 1, nobody notices. Safe to run on a live app with real users signed in right now. Nothing they are doing breaks. Items 4, 18, 2, 3, 14, 15, 19, 12 and 13.
Wave 2, people get logged out. Each of these either ends existing sessions or changes where the session lives. Do them when the app is quiet, one at a time, testing after each. Items 9, 7, 8, 16, 11, 10, 1 and 17.
Wave 3, needs you, outside the chat. The AI writes the code and the job still is not done. Items 5, 6, 20, and the email half of 13.
If you only have time for two, do 13 and 2. Those are the two costing you customers today, because a user who cannot get back in leaves without telling you.
Warning 1, four of these can lock you out of your own app. Items 9, 7, 16 and 1 all touch what is keeping you signed in. Item 9 moves the token somewhere else, so existing sessions stop working. Item 1 can lock out every account created before verification existed, including yours, if the AI marks them all unverified. Before running any of the four, have a second browser window signed in, know your own password, and confirm the reset flow from item 13 already works. Add this line to those prompts:
Existing accounts must stay usable. If this change would invalidate
existing users or sign anyone out, tell me first and wait.
Warning 2, the reset email is not an AI problem. Item 13's prompt produces working code in two minutes and the mail can still land in spam or nowhere. Delivery needs a real sending domain and DNS records, SPF, DKIM and DMARC, set up wherever you send mail from. No AI can do that part. A reset flow you have never personally received a mail from, at two different mail providers, is not built.
Warning 3, item 6 written the obvious way is a weapon pointed at your users. Locking an account after repeated failures sounds strictly safer. It is not. If anyone can lock any account by typing a known address and ten wrong passwords, you have handed every stranger a button that locks your users out. The prompt below makes the lock temporary and escalating, and pairs it with item 5, which is the part that actually stops an attack.
Warning 4, a rate limit that resets on every deploy is not a rate limit. If attempts are counted in memory, the count dies on each deploy and does not exist across instances at all, so ten instances means ten times the attempts. The prompt below makes the AI say where the counter lives. Read that answer before ticking the box.
Get in
Six items around the part the AI actually built.
1. Verify the email before first login
Without it: anyone can sign up as anyone. Someone can make an account on your app with your email address today, and tomorrow that account is theirs.
Add email verification to sign-up, using whatever auth and email setup
this project already has. Do not install a new auth library. On sign-up,
send a verification link and show a "check your email" screen. An
unverified user must not be able to use the app; show that screen with a
clear message rather than a generic error. The token must be random,
single use, stored hashed, and expire in 24 hours. Existing accounts must
stay usable: if this would mark current users unverified and lock them
out, tell me first and wait. Do not touch the password or session code.
Verify: sign up with a spare address, do not open the inbox, and try to log in. You should land on “check your email”, not inside the app and not on a crash. Then open the mail, click the link, and log in. And check your own account still works.
2. Resend the verification link
Without it: the mail went to spam or the link expired, and the user is stuck on “check your email” forever. They signed up and never got in, and you will never hear about it.
Add a "resend verification email" button to the "check your email" screen
and to the expired-link page. Each resend invalidates the previous link so
only the newest works. Rate limit resends to 1 per minute and 5 per hour
per address, and show a friendly countdown rather than an error when
someone hits the limit. The response must look identical whether or not
that address has a pending account. Do not change the sign-up flow itself.
Verify: click resend and a second mail arrives. The link in the first mail must now fail onto a page that offers a fresh one, not a blank error. Click resend twice more quickly and the third should ask you to wait, in words, rather than showing a raw error code.
3. Expire verification links in 24 hours
Without it: a link mailed six months ago still works. That mail sits in an inbox, gets forwarded, ends up in a screenshot, and it is still a way into the account.
Make verification links expire 24 hours after they are sent, with the
expiry as a single configurable value in one place. An expired link must
land on a page that says it expired and offers a new one, never a blank
page, a 500, or a generic "invalid token". Tell me the exact file and line
where the expiry value lives. Do not change the link format or the email
copy.
Verify: ask where the value lives, set it to one minute, request a link, wait, and click it. You should get the expired page with a resend button. Then set it back and confirm it is back.
4. Say “wrong email or password”, never which one
Without it: your login form answers the question “does this person have an account here?” for anyone who asks, and a script can ask it ten thousand times and leave with a list of your users.
Make login failures identical whether the address does not exist or the
password is wrong: same message, same status code, same page. Make them
take a similar amount of time too, by running a dummy password comparison
when the address is not found, so response time does not reveal which
accounts exist. Audit every other place that leaks the same thing: sign-up,
password reset, and any email-availability check. Tell me each place you
found and what you changed it to. Do not change what a successful login
does.
Verify: try a made-up address, then your real one with a wrong password. Identical message and roughly the same delay, because if one answers instantly and the other takes half a second, the timing is still telling. Then sign up with an address you know exists, which should say something like “if this address is new, check your inbox” rather than “already registered”.
5. Rate limit login attempts
Without it: a script tries a thousand passwords a minute, all night, against every address from item 4's list, and nothing stops it or tells you it happened.
Add rate limiting to login, per IP address and per account, both.
Suggested limits are 5 failed attempts per account per 15 minutes and 20
per IP per 15 minutes. Tell me whether this project's hosting has a better
place to do this than the app code. Tell me explicitly where the counter
is stored, and whether it survives a deploy and works across multiple
instances; if it is only in memory, say so plainly and tell me what this
project would need instead. Apply the same limit to password reset and
verification resend. Successful logins must not be slowed. Do not lock any
account permanently.
Verify: a wrong password six times in a row should be refused with a message saying how long to wait. Then try from your phone on mobile data with a different account, which must still work, proving the limit is per account and per address rather than a switch that took your whole login offline. Read the answer about where the counter lives before ticking this one.
6. Lock after repeated failures, and unlock by email
Without it: item 5 slows an attacker down but does not stop a patient one running six attempts an hour for a month.
After 10 failed logins on one account, apply a temporary lock, not a
permanent one: 15 minutes, doubling for each further round of failures,
capped at 24 hours. Email the account owner when a lock starts, saying
someone has been trying to sign in, with a link that unlocks immediately
if it was them. A successful login clears the counter. Never lock an
account permanently and never require support to unlock it, because anyone
can type a stranger's address and ten wrong passwords, so a permanent lock
is a way to attack my users. Send at most one lock email per account per
hour. Do not change the login error message.
Verify: lock a spare account on purpose. The login screen should say the lock is temporary and roughly how long, a mail should arrive, and the unlock link should get you straight back in. Then wait out the window and confirm it clears on its own.
Stay in
Six items where nothing breaks. No error, no crash, no complaint. The user quietly stops coming back. These are all wave 2, so read warning 1 first.
7. Keep users signed in for 30 days
Without it: every visit starts with a login screen. The apps people open daily do not ask for a password every time, and yours asking is the reason the second visit does not happen.
Keep users signed in for 30 days across browser restarts, using a
long-lived refresh token plus a short-lived access token, not by making
the access token last 30 days. Rotate the refresh token on every use and
invalidate the old one. Add a "remember me" choice at login, where
unchecked means the session ends when the browser closes. Tell me first if
this change signs out everyone currently logged in. Do not change the
password or verification code.
Verify: sign in with “remember me”, close the browser entirely, reopen, and return. Still signed in. Then leave it a day and check again, because a session that survives a restart but not a night is not 30 days.
8. Refresh sessions silently
Without it: the session dies mid-task. Ten minutes filling a form, hit save, login screen, everything gone. That user does not type it again.
Refresh the access token in the background before it expires, with nothing
visible to the user: no flash of a login screen, no redirect, no lost
work. If a request fails because the token just expired, refresh once and
retry that request automatically instead of bouncing the user to login. If
the refresh genuinely fails, then log them out, and only then. Make sure
two tabs refreshing at once do not fight or invalidate each other. Do not
extend the token lifetime as a workaround.
Verify: ask for the access token lifetime, then start typing into a form and leave the tab alone for longer than that. Come back and submit. It must save. A login screen or an error means this is not done.
9. Store sessions in httpOnly cookies, not local storage
Without it: any script on your page can read the token, whether from a bad dependency, an injected ad, or user content rendered raw. Whoever has the token does not need the password, because they are that user. If the difference between the two storage choices is new to you, JWT versus session authentication walks through it with a diagram.
Move the session from local or session storage into httpOnly cookies. The
cookie must be HttpOnly, Secure, SameSite Lax or Strict, with a sensible
path and expiry. Afterwards no token may be readable from JavaScript
anywhere in the app. If SameSite or a cross-domain API would break
something here, such as a separate API domain, a mobile app or a browser
extension, tell me before changing anything and wait. Add CSRF protection
at the same time, since cookies are sent automatically. This will sign out
everyone currently logged in, so confirm with me first.
Verify: sign in, then open the browser’s storage panel. Nothing that looks like a token. In the console, print the document cookies: your session cookie must not appear there, because if it does, HttpOnly is not set. Then check the cookie itself shows HttpOnly, Secure and a SameSite value. Finally sign in and out twice to confirm nothing else broke.
10. Send expired sessions back to the page they were on
Without it: someone clicks a link to a specific page, gets the login screen, signs in, and lands on the home page. Now they have to find the thing again, and half of them do not.
When a logged-out user hits a page that needs login, remember where they
were going and send them back there after they sign in. Only allow
same-origin relative paths as the destination, and reject anything with a
domain, a protocol or a double slash, so this cannot redirect someone to
another site after login. Apply it to shared links too, so a link to a
deep page opened by a logged-out person goes to login and then to that
page. Do not change the login form for people who came to it directly.
Verify: log out, paste the URL of a deep page, and you should get login and then that page. Then try putting another site’s address in the return parameter. You must end up on your own app. That second check is the whole reason this prompt is longer than it looks.
11. Add “log out everywhere”
Without it: a lost phone, or a laptop at an office someone has left, stays signed in forever. The user can see the problem and has no button to fix it.
Add a "log out of all devices" action in account settings that immediately
invalidates every session for that user on every device. This needs
sessions tracked server-side rather than only self-contained tokens, so
tell me how this project tracks them today and what has to change. Give me
the option to keep the current device signed in and make that the default,
so nobody logs themselves out of the page they are standing on. Show a
confirmation before it runs. Do not change how normal logout works.
Verify: sign in as the same user in a normal window and a private one. Use the button in the normal window, then refresh the private one and click something. It must ask for a login, and your own window must still be signed in.
12. Show active devices
Without it: “log out everywhere” tells a user something might be wrong. This is the page that tells them what.
Add an active-sessions list in account settings. For each session show the
device and browser, approximate location from the IP address, when it
started, when it was last used, and which one is the current session. Add
a sign-out button per row. Do not display full IP addresses, only city and
country level. Do not store more about a device than this list needs, and
tell me exactly what fields you are now storing and where.
Verify: sign in from your phone on mobile data, then open the list on your laptop. Two rows, the current one marked, the phone in a different place. Sign the phone row out from the laptop and refresh the phone, which should show a login screen.
Get back in
Everything behind the “forgot password?” button the AI drew and did not wire up.
13. Reset password by email
Without it: a user who forgot their password has one route back in, which is emailing you and waiting. You are asleep, and by morning they have moved on.
Build a full password reset flow using whatever email setup this project
already has: a "forgot password" form, a mailed link, a set-new-password
page, and a confirmation. The token must be random, at least 32 bytes,
stored hashed, single use, and tied to one account. The new-password page
must enforce the same rules as sign-up. After a successful reset, either
sign the user in or send them to login with a clear success message, and
do not leave them on a blank page. Tell me which email service this
project is actually configured to send through, and whether it sends from
a real domain or is still on a test sender. Do not add security questions
or an SMS fallback.
Verify: do the full round trip with a spare address, timed. The mail arrives inside a minute, the link sets a new password, the new password works and the old one does not. Then repeat it at a different mail provider, and read item 21 below before ticking this.
14. Expire reset links in 15 minutes
Without it: a reset link is a way into an account without a password, so one sitting in an inbox from last year is still a working key.
Make password reset links expire 15 minutes after they are sent, with the
expiry as one configurable value. An expired link must show a page that
says so and offers a fresh link in one click, not a blank page, not
"invalid token", not a crash. Requesting a new reset link must invalidate
every earlier one for that account. Tell me the file and line where the
expiry lives. Do not change the verification link expiry, which is a
separate value.
Verify: set it to one minute, request a link, wait, and click. You should get the expired page with a one-click resend. Then set it back and request two links in a row, where the first must now be dead and the second alive.
15. Make reset links single use
Without it: the user resets their password and the link still works, for them and for anyone else with access to that inbox, any number of times.
Make each password reset token usable exactly once. Mark it used the
moment the password changes and reject it after that, including when
someone presses the browser Back button and submits the form again. Also
invalidate every other outstanding reset token for that account at the
same time. A reused link must land on a page explaining it has already
been used, with an offer of a new one. Do not change the expiry logic,
which is a separate item.
Verify: use a reset link fully, then press Back, land on the set-password page again, and submit a different password. It must fail with a readable page. Then confirm the password from the first reset still works, because if the second attempt quietly changed it, this is not done.
16. End every session after a password change
Without it: an account was taken, the owner did the right thing and changed the password, and the attacker is still signed in on their own machine. The password change achieved nothing.
When a password changes, by reset or from settings, invalidate every
existing session for that user on every device immediately. Keep only the
session that made the change signed in, so the user is not logged out of
the page they are standing on. Do the same for an account-email change.
Tell me first if this affects sessions currently active in production. Do
not change the password rules themselves.
Verify: sign in as the same user in two browsers, change the password in one, then click anything in the other. It must ask for a login, and the browser that made the change must stay signed in.
17. Confirm email changes from the old address
Without it: someone gets five minutes with an unlocked phone, changes the account email to their own, and then resets the password. Every recovery route now points at them.
Change the account-email flow to two steps. First, send a confirmation
link to the NEW address and change nothing until it is clicked. At the
same time, send a notice to the OLD address saying the email is being
changed, to what address, with a link that cancels the change and locks
the account if it was not them. The old address stays the login until the
new one is confirmed. Require the current password before the change can
be requested. Expire both links in 15 minutes. Do not let an unconfirmed
change stop the user logging in with their old address.
Verify: change your email to a spare address and check both inboxes, where you should find a confirm link in the new one and a warning in the old one. Before clicking confirm, log out and log back in with the old address, which must still work. Then click the cancel link in the old inbox and confirm the change is dead.
18. Never reveal whether an email is registered
Without it: you fixed the leak on the login page in item 4, and the forgot-password page is still answering the same question for anyone who asks.
On the forgot-password page, return the same message for every address,
such as "if an account exists for this address, we have sent a link",
whether or not the account exists, and take roughly the same time either
way by doing the same work in both paths. Do the same audit for sign-up,
email change, any email-availability endpoint, and any API route that
takes an address. List every place you found and what it says now. Keep
the message human, so it does not read like an error. Do not change the
mail that real accounts receive.
Verify: request a reset for an address with no account, then for your real one. Identical message, similar delay. The real one gets a mail and the other gets nothing. If the unknown address ever receives a “you do not have an account” mail, that is the same leak with extra steps.
The account is theirs
Two items, and they decide whether someone recommends your app or warns people off it.
19. Email the user on every password or email change
Without it: an account is taken and the owner finds out the next time they try to log in, which may be a week later.
Email the account owner whenever the password changes, the account email
changes, two-factor changes, or a new device signs in for the first time.
On an email change, send to the OLD address as well as the new one. Each
mail says what changed, when, and roughly from where and on what device,
and gives a one-click "this was not me" link that locks the account and
starts a reset. Send these even when the change came from the user's own
settings page, because a confirmation is not spam. Never put the password,
the token or the reset link itself into these mails.
Verify: change your password from settings. A mail arrives within a minute, names the device and rough time, and has a “this was not me” link. Click that link on a test account and confirm it really locks the account, because a notification with a dead button is worse than no notification.
20. Let users delete their account
Without it: someone who has decided to leave cannot, and they will remember that. If you have a mobile app it is not optional either. Apple has required in-app account deletion for apps that support account creation since June 30, 2022, and Google Play requires both an in-app path and a web link where people can request deletion, enforced since May 2024.
Add account deletion in settings: a clear button, a confirmation step that
asks for the password, then immediate sign-out on every device. Implement
it with a 30-day grace period, where the account is deactivated and
unusable at once, a mail goes out with a restore link, and everything is
permanently deleted after 30 days. Before writing anything, list every
table and every external service holding this user's data, and tell me
what happens to each one: deleted, anonymized, or kept because the law
requires it. Do not delete anything the business genuinely must keep, such
as invoices; anonymize those instead and tell me which ones you treated
that way.
Verify: delete a test account. You are signed out everywhere, the old password does not work, and the restore mail arrives. Then try signing up again with that address, which should work rather than collide with the deactivated account. Read the list of tables and services before you run this one, because that list is the real deliverable.
Two more that decide whether the rest works
21. Check the mail actually arrives
Items 1, 2, 13 and 19 all ship working code and the user can still get nothing. Sending mail that lands in an inbox is not code, it is a domain, and it is the most common reason a finished reset flow fails in the wild.
Tell me exactly how this project sends email right now: which service,
which sending address, and whether that address is on a domain I own or on
the provider's test sender. If it is a test sender, say plainly that mail
will only reach addresses I have verified and will not reach real users.
Then list, in order, what I have to do in the provider's dashboard and my
DNS to send from my own domain, covering SPF, DKIM and DMARC, and how I
check each one is live. Do not change any code in this reply, and do not
tell me it is working until I confirm a test mail landed.
Verify: send yourself a reset mail at one large mail provider and at one other, such as a work address. Both must land in the inbox rather than spam, within a minute. Then open the message’s original headers and confirm SPF, DKIM and DMARC all pass. Anything less and your reset flow is decorative.
22. Stop logging the tokens
It all works, and your server logs are now a list of working keys to your users' accounts. AI-written auth prints tokens while debugging and the prints stay in.
Search this whole project for anywhere a password, session token, refresh
token, reset link, verification link or one-time code could end up in a
log, an error message, an analytics event, or an error-tracking service.
Include full URLs, since reset links contain the token. List every place
with its file and line, then replace each value with a redacted marker
such as "[token]" or "[set]". Check what the error tracker is configured
to capture from request bodies and headers. Do not remove logging that is
actually useful, only the values.
Verify: trigger a password reset, then search your server logs for the token from the link in your inbox. If you can find it, anyone with log access can take that account. This is the same habit as the security checklist, which covers the keys and the database around it.
Make it stick
Put this in your tool’s project instruction file, such as CLAUDE.md, AGENTS.md or
your editor’s rules file, so the next auth change does not undo this afternoon’s work.
The 5-file starter pack explains where it
goes.
AUTH RULES FOR THIS PROJECT
- Sessions live in httpOnly, Secure, SameSite cookies. Never in local or
session storage.
- Login, sign-up and password reset never reveal whether an address is
registered. Same message, same status, same timing.
- Every token, whether verification, reset or invite, is random, stored
hashed, single use, and has an expiry.
- Password reset links expire in 15 minutes. Verification links expire in
24 hours.
- Changing a password or an account email invalidates every other session
for that user.
- Email the account owner on every password change, email change and
new-device login. Send to the old address too.
- Never log, print or send to an error tracker: passwords, tokens, reset
links, verification links, one-time codes or full request bodies.
- Rate limit login, password reset and verification resend, per IP and per
account. Say where the counter is stored.
- Account locks are temporary and escalating. Never permanent, never
support-only.
- Before any auth change that could sign out existing users, say so and
wait for me.
To confirm it is being read, open a new chat and ask what the auth rules in this project are, and to list them from memory before doing anything. A generic answer means the file is not being picked up, so check its name and that it sits in the project root.
What this is, and what it is not
Twenty prompts are not a security audit. They close the gaps AI leaves in the login it writes. They do not cover authorization, which is whether a signed-in user can reach someone else’s data by changing an ID in the address bar, and that is the one that actually leaks records. The security checklist is where that lives.
Fifteen minutes is the prompts, not the job. Wave 1 really is one sitting. Wave 2 needs a quiet app and a test after each item. Wave 3 needs a DNS panel and a decision about your users' data. Anyone saying all twenty are fifteen minutes has never watched a reset mail land in spam. If the login worked on your machine and broke once it was live, the deploy guide covers that gap, and if the agent starts going in circles while you work through this, the loop breakers are the way out.
The AI is marking its own homework. Every prompt fences what it may touch and every item has a check, for the same reason: “done” from a chat is a claim, not a fact. “It says the reset flow is built” is not a check. “A mail arrived at my other address in forty seconds and the link worked once and then failed” is.
Three things that are true and inconvenient. A permanent account lock is a weapon your users can be hit with. A rate limit held in memory is a comment, not a limit. And a password reset you have never personally received a mail from does not exist.
One last thing worth saying plainly. If you reach item 11 and the project has no server-side session store at all, or item 17 and there is no email infrastructure to speak of, that is the point where a managed auth provider may cost less than the next four items. Ask the AI directly whether it is cheaper to finish the list or to move, and to give you the real migration cost rather than the marketing answer. Moving is not defeat. Shipping the half-built version is.
Your test account never forgets its password, never changes phone, and never comes back a month later. Every real user does all three.
Common questions
- Why does my AI-built login work in testing but fail with real users?
- Because you tested it with a test account, and a test account never forgets its password, never changes phone and never comes back a month later. Real users do all three. AI reliably builds the happy path, so sign-up and login work on the first try, while password reset, email verification, session length and account deletion are missing or half-wired.
- What is the most important thing missing from an AI-built login?
- A password reset that actually delivers an email. A user who cannot get back in is gone, and they will not email you about it. Test the whole round trip yourself with a spare address, at one big mail provider and one other, and confirm the link works once and then stops working.
- Why do my password reset emails go to spam?
- Because delivery is not a code problem. Mail lands in inboxes when it is sent from a domain you own with SPF, DKIM and DMARC records set up in your DNS, and many projects are still sending from a provider’s test sender, which only reaches addresses you verified. No AI can do that part for you, so the code can be finished while the feature is not.
- Can adding these things lock me out of my own app?
- Four of them can. Moving sessions into cookies, changing session length, invalidating sessions on password change and adding email verification all touch what is keeping you signed in right now. Before running any of those, have a second browser signed in, know your own password, confirm password reset already works, and tell the AI that existing accounts must stay usable.
Keep reading
Your AI agent is stuck in a loop: 12 prompts that break it
Twelve copy-ready prompts for when your AI agent keeps saying it fixed the bug and ships the same fix, cheapest first, each with a way to tell it worked.
12 security holes AI leaves in your app, and how to close them
A copy-ready prompt to close each of the twelve security holes AI leaves in most apps, and a browser check under each one to prove it actually shut.
You launched and nobody signed up: 10 reasons and the fix
Ten reasons nobody signed up, the move for each and how to tell it worked, plus twenty launch angles and where to find people already complaining.