Add user login safely to an AI-built app
You ask your AI agent to "add login", and a few minutes later there's a sign-in page. It looks finished. But login is where an app decides who someone is and what they can see, and small mistakes there can show one user's data to another.
This guide is a checklist of 8 checks for anyone building a small web app with AI coding agents. It's quoted from OWASP, MDN, Supabase, Firebase and Auth.js docs, checked Oct 2026.
Not affiliated with or endorsed by the OWASP Foundation, Mozilla, Supabase, Google/Firebase or Auth.js. Check their current docs before relying on these details.
Keys and exposed databases are covered elsewhere. See Keep secrets safe with AI coding tools and Before you ship: lock the database, back it up, and log what happens. This guide doesn't repeat them.
Part 1: Don't start from scratch
Check 1: Use a login service or library, not home-made code
Our advice, not a vendor quote: don't build your own login. Use a managed login service or an established library, and let it handle the hard parts.
Managed services exist for this. Supabase says "Supabase Auth makes it easy to implement authentication and authorization in your app." (source) Libraries do too. As one example, Auth.js describes itself as "a runtime agnostic library based on standard Web APIs that integrates deeply with multiple modern JavaScript frameworks". (source)
Even small details are better left to tested code. OWASP says "the user-supplied password should be compared to the stored password hash using a secure password comparison function provided by the language or framework, such as the password_verify() function in PHP." (source)
- Your app signs people in through a login service or an established library.
- Your agent hasn't written its own password checking from scratch.
Check 2: If you store passwords, hash them with a slow algorithm
If passwords end up in your own database, they must never be stored as plain text. OWASP says "they must be protected using strong, slow hashing algorithms such as Argon2id, bcrypt, or PBKDF2." It explains why: "Using slow, memory‑hard algorithms makes brute‑force attacks significantly more difficult, expensive, and time‑consuming." (source)
OWASP's settings: "To sum up our recommendations: Use Argon2id with a minimum configuration of 19 MiB of memory, an iteration count of 2, and 1 degree of parallelism." And: "For legacy systems using bcrypt, use a work factor of 10 or more and with a password limit of 72 bytes." (source)
OWASP's Top 10 lists apps that "Uses plain text, encrypted, or weakly hashed passwords data stores" as a login failure. (source) Note that "encrypted" is on that list. OWASP explains: "Since encryption is a two-way function, attackers can retrieve the original plaintext from the encrypted data." (source)
It also flags apps that "Permits default, weak, or well-known passwords, such as 'Password1' or 'admin/admin'." (source)
- No password is stored as plain text or with reversible encryption.
- If you hash passwords yourself, you use Argon2id, bcrypt or PBKDF2 with OWASP's settings.
- Your app refuses weak or default passwords.
Part 2: The sign-in form
Check 3: Give the same error for a wrong email and a wrong password
If your form says "no account with that email", an attacker learns which emails are real. OWASP says "An application should respond (both HTTP and HTML) in a generic manner." It adds that login, password reset and password recovery "must respond with a generic error message regardless of whether" the user ID or password was wrong or the account doesn't exist. (source)
- Login, password reset and recovery all show the same message whether or not the account exists.
Check 4: Limit login attempts
Attackers try many passwords, or reuse leaked ones. OWASP's Top 10 warns against apps that permit "automated attacks such as credential stuffing, where the attacker has a list of valid usernames and passwords." (source)
OWASP describes the defense: "Login Throttling is a security mechanism used to prevent an attacker from making too many attempts at guessing a password through normal interactive means". It also says "The most common protection against these attacks is to implement account lockout, which prevents any more login attempts for a period after a certain number of failed logins." (source)
Our advice, not a vendor quote: this guide doesn't give numbers for limits or lockouts. Check your login service's settings to see what it already limits and what you can change.
- You've checked your login service's attempt-limit settings and turned them on.
Part 3: Staying signed in
Check 5: Lock down session cookies
After sign-in, a cookie usually keeps the user logged in. MDN explains three settings:
- Secure: "A cookie with the Secure attribute is only sent to the server with an encrypted request over the HTTPS protocol."
- HttpOnly: "You can prevent JavaScript from accessing a cookie by specifying the HttpOnly attribute during its creation."
- SameSite: "SameSite helps to prevent leakage of information, preserving user privacy and providing some protection against cross-site request forgery attacks." (source)
OWASP agrees that HttpOnly "instructs web browsers not to allow scripts" to read the cookie. (source)
Renew the session when someone signs in. OWASP says "The session ID must be renewed or regenerated by the web application after any privilege level change within the associated user session." And "The most common scenario where the session ID regeneration is mandatory is during the authentication process". (source)
Keep it out of links, too. OWASP's Top 10 lists apps that "Exposes session identifier in the URL." (source)
- Session cookies are set with Secure, HttpOnly and SameSite.
- The session is renewed at sign-in.
- No session ID appears in a URL.
Check 6: Offer two-step login, and know what counts
OWASP says "Multifactor Authentication (MFA) requires evidence from at least two distinct authentication factors: something you know, something you have, and something you are." A password plus a PIN isn't MFA: "requiring multiple instances of the same authentication factor (such as needing both a password and a PIN) does not constitute MFA and offers minimal additional security." (source)
The Top 10 counts it as a failure when an app "Has missing or ineffective multi-factor authentication." (source) OWASP is honest about the cost: "The biggest disadvantage of MFA is the increase in management complexity for both administrators and end users." (source)
- Users can turn on a second factor of a different kind, such as a code from their phone.
- Admin accounts use it.
Part 4: Who can see what
Check 7: Tie your database to the signed-in user
Login only tells you who someone is. Your database still has to decide what they can see.
Supabase: "Auth integrates with Supabase's database features, making it easy to use Row Level Security (RLS) for authorization." (source) In those rules, "auth.uid() returns the ID of the user making the request." Supabase warns that "A table in an exposed schema without RLS is readable and writable by any role with a grant on it." Its advice: "Enable RLS on every table in an exposed schema." It also says the service_role role has "Full access. It bypasses RLS, so keep it server-side". (source) For RLS basics see lock the database, and for handling the service key see Keep secrets safe.
Firebase: Firebase's basic rules page shows this example (we haven't tried it ourselves):
// Allow only authenticated content owners access
allow read, write: if request.auth != null && request.auth.uid == userId
(source)
Watch for open rules left over from building. Firebase says "As you set up your Firebase project, you might have set your rules to allow open access during development." and warns: "If you're not authenticating users and configuring security rules, then anyone who guesses your project ID can steal, modify, or delete the data." (source)
- Every Supabase table in an exposed schema has RLS on, with rules that use
auth.uid(). - The service_role key never reaches the browser.
- Firebase rules check
request.auth, and no open development rules remain.
Check 8: Check permissions on the server, every time
OWASP says "Permission should be validated correctly on every request, regardless of whether the request was initiated by an AJAX script, server-side, or any other source." And: "The application must always make a decision, whether implicitly or explicitly, to either deny or permit the requested access." (source)
Our advice, not a vendor quote: hiding a button isn't a check. Anyone can send the request the button would have sent, so the server has to check it. See How to review AI-written code for checking what your agent wrote.
- Every server route that reads or changes data checks who the signed-in user is and what they're allowed to do.
- When in doubt, the route says no.
Ask your agent to review your login
Give your agent a prompt like this (we haven't tried it ourselves):
Review how this app handles sign-in. Use the existing auth provider
rather than custom password code. Check that login, reset and
recovery return the same generic error, that login attempts are
limited, that session cookies are HttpOnly, Secure and SameSite and
the session is renewed at sign-in, and that every server route and
database rule checks the signed-in user (RLS with auth.uid() or
Firebase rules with request.auth). List the problems and proposed
changes before editing anything, and don't touch the live database
or any keys.
See AI agent permissions for beginners to make the agent ask before it changes anything.
Next steps
- Lock the database: lock the database, back it up, and log what happens
- Protect your keys: keep secrets safe with AI coding tools
- Review the code: how to review AI-written code
Sources
All checked Oct 2026:
- OWASP Password Storage Cheat Sheet
- OWASP Authentication Cheat Sheet
- OWASP Session Management Cheat Sheet
- OWASP Multifactor Authentication Cheat Sheet
- OWASP Authorization Cheat Sheet
- OWASP Top 10 2021, A07 Identification and Authentication Failures
- MDN, using HTTP cookies
- Supabase Auth
- Supabase Row Level Security
- Firebase basic security rules
- Firebase, avoid insecure rules
- Auth.js getting started
Not affiliated with or endorsed by the OWASP Foundation, Mozilla, Supabase, Google/Firebase or Auth.js. Check their current docs before relying on these details.