Two access failures ran through the 21 third-party apps I audited in June and July 2026: in 7, a logged-in user could read or write another customer’s data, and 11 had unauthenticated endpoints doing privileged work. Neither shows on a login screen. This authentication checklist is the 11 controls that close both, each with a test you can run.
What this authentication checklist covers
An authentication checklist for one app is 11 controls: every login flow including its failure paths, session expiry and revocation, server-side authorization, data isolation across every table, protected admin actions, abuse limits, a written role model, complete account deletion, session listing and global sign-out, a sensitive-action audit log, and two-factor for owners and admins.
Those 21 were a selected set of third-party apps I audited, not a random sample, so the 7 and the 11 describe that group and are not a rate for AI-built apps in general. Access control sits first in production hardening because it answers the question every other area depends on: who can reach the data. It holds 11 of that list’s 123 deliverables.
The table gives each control, what it asks for and why it matters, with the topic that goes deeper on it.
| Control | What it is | Why it matters | Deeper topic |
|---|---|---|---|
| 1. Login flows | Review and fix signup, login, logout, password reset, email verification, and OAuth callbacks | Broken account flows can lock out customers or allow unauthorized access | authentication best practices |
| 2. Sessions and tokens | Verify expiry, refresh, and session revocation on logout and password change | An old session can remain usable after an account owner tries to secure it | JWT security |
| 3. Server-side authorization | Enforce permissions on every protected route, API endpoint, and server action | A hidden button does not prevent a direct request to the backend | broken access control |
| 4. Data isolation | Implement and test Row-Level Security or equivalent server-side scoping across all tables, with explicit rules for intentionally public data | Missing data boundaries can expose one customer’s records to another | multi-tenant data isolation |
| 5. Admin actions | Restrict admin routes and operations to explicit, verified roles | Unprotected administrative actions can let ordinary accounts change or delete important data | admin panel security checklist |
| 6. Abuse limits | Implement rate limits and brute-force protections on authentication and recovery endpoints | Automated login attempts can compromise accounts or overwhelm account services | brute force login protection |
| 7. Role model | Write a one-page matrix defining roles and their permitted actions | Ambiguous permissions create inconsistent behavior as the product grows | RBAC examples |
| 8. Account deletion | Build the account deletion flow, covering related records and stored assets under the documented retention rules | Removing a profile alone can leave personal data scattered through the system | account deletion feature |
| 9. Session management | Provide session listing and a way to sign out across all active sessions | Users need a way to remove access from lost devices or unfamiliar sessions | what is active session management |
| 10. Audit log | Log role changes, deletions, and billing changes with the actor, action, and time; protect access to the log | Important changes are difficult to investigate without a reliable activity record | audit logging best practices |
| 11. Two-factor for admins | Enforce a second factor on every owner and admin account, in the application and on every provider dashboard behind it, with recovery codes stored in the owner’s vault | One leaked password on a dashboard account is a full takeover of the product and its data | implement two-factor authentication |
If launch is a week out, the authentication flow checklist before launch is my grouping of controls 1, 2, 6 and 11, run in the week before real users arrive, because those are the parts a new user or an attacker touches first.
Authentication verification: authentication, authorization and verification, three jobs
Authentication verification covers three separate jobs. Authentication verifies who you are each time you sign in, authorization is the decision to permit or deny what you do once you are in, and verification proves a single claim, such as an email address or a phone number, once. The controls on this page cover all three.
NIST’s glossary defines authentication as “Verifying the identity of a user, process, or device, often as a prerequisite to allowing access to resources in an information system.” In a SaaS, that is the sign-in: the password, magic link or Google button that turns a visitor into a known user.
Authorization, in the same glossary, is “The decision to permit or deny a subject access to system objects (network, data, application, service, etc.).” In a SaaS, it is the server deciding that this request, from this user, may touch this row in this workspace. The role authorization plays is keeping customers apart, and it is the job that failed in 7 of the 21 apps in the same audits.
Verification is the word that drifts. NIST’s glossary uses it for identity proofing: confirming that an applicant holds the real-life identity they claim. A SaaS usually needs a smaller version, the email link clicked once to prove an address belongs to the person signing up. Authorization verification, in the sense this page cares about, means testing that the server really refuses what the role model says it should refuse, which is what controls 3, 4, 5 and 7 do.
A fourth word gets mixed in: authentication and validation are different jobs, and validation means checking that input is well formed before the app uses it. That belongs with input handling, not login. Authentication is important for a plainer reason than any definition: everything after it trusts its answer, so the role check, the audit log and the billing record all inherit whatever user id the sign-in produced.
How to do authentication: the factor types and the methods a small SaaS chooses between
How to do authentication: pick methods across three factor types, something you know, something you have, and something you are. A small SaaS picks from five methods: a password, a magic link, sign-in with Google or GitHub, a passkey, and a second factor from an app or SMS. Owner and admin accounts always get the second factor.
The factor types come from NIST SP 800-63B, the revision published with the SP 800-63-4 guidelines in 2025, whose glossary names 3 types of authentication factors: “The three types of authentication factors are something you know, something you have, and something you are.” CISSP study material numbers the same three as Type 1 (know), Type 2 (have) and Type 3 (are), so an authentication factor type 1, 2 or 3 in a course means one of these. Counts of 4 types of authentication, or five, are not NIST’s factor types, and some count methods instead: WorkOS’s list of five, for example, sorts authentication methods into username and password, multi-factor, token-based, certificate-based and biometric.
The table below covers the types of authentication methods for web applications that a small SaaS actually chooses between. The factor column follows NIST’s definitions; the when-it-fits column is my reading, for a small team.
| Method | Factor type | When it fits a small SaaS |
|---|---|---|
| Password | Something you know | Fine as the base method once control 6 is in place and admins add a second factor |
| Magic link | Access to an inbox, closest to something you have; NIST rules email out for out-of-band authentication | Low-stakes apps where users sign in rarely and forget passwords |
| Sign-in with Google or GitHub | Whatever the provider checked; your app receives an assertion from it, not a factor of its own | Apps whose users already live in those accounts; one fewer password table to guard |
| Passkey | Something you have, unlocked by something you know or something you are | Apps that want phishing resistance and can support it on every device their users bring |
| Second factor by app or SMS | Something you have | Every owner and admin account; on Supabase, phone MFA is a priced add-on whose pricing table lists the Pro, Team and Enterprise plans, while the app-code factor is free and on by default, so an app code is where a free project starts; NIST treats codes sent over the phone network as a restricted authenticator |
No source in my research states which method is the most common authentication method, so I will not guess one. The same goes for what is the best authentication method in general: the useful answer is which of the five fits the app in front of you, and the right column is my attempt at that. I leave out other web page authentication methods, such as client certificates, because this table is for a small SaaS. Password length and composition rules are a separate topic, NIST minimum password length, and the second factor for admins is control 11 below.
What goes wrong without it
These four access risks can ride through a demo unnoticed, because each needs a second account, a direct request or an old session to show itself. Each one below starts with what you would see, then the cause and the page to open.
A customer can see another customer’s data
A logged-in user opens a list, changes a filter or an id, and sees rows that belong to someone else’s account, or edits them. That is the opener’s 7 of 21: confirmed cross-user or cross-tenant authorization failures, in the same audits. In those same audits, 9 of the 21 apps had row-level security gaps. The version where a request carries another customer’s id and the server simply serves it has its own name: IDOR, the insecure direct object reference.
A public record shows how small the gap can be. The NVD record for CVE-2026-77240 describes WACRM, a self-hostable CRM template for WhatsApp whose database rules live in Supabase migrations: in version 0.7.0 and earlier, its profiles_update row-level security policy “permits authenticated users to modify their own account_role and account_id, allowing a viewer to self-promote or move into another tenant and then access or modify tenant resources.” NVD published the record on September 18, 2026; the flaw was reported through GitHub’s security advisories, and the record names the commit that fixes it. The lesson I take from it: a row-level policy that checks whose row it is, but not which columns change, hands the user their own role and tenant id. Testing tenant boundaries in depth is the job of the multi-tenant data isolation page.
The API does admin work for anyone who calls it
An endpoint deletes a record, changes a plan or starts a paid job when nobody is signed in, or it believes a role or a price that the browser sent. In the same audits, 11 of the 21 apps had endpoints that did privileged work with no signed-in user at all. And 10 of the 21 trusted the client: the server accepted whatever the browser asserted.
One way it happens: a button is hidden in the interface while the route behind it stays open, the gap control 3’s row in the table describes. The broken access control page and the admin panel security checklist go deeper on each half. The two-account test that proves an API refuses the wrong caller is already written up in the API security checklist; run it from there rather than from a summary here.
Logins get brute-forced or stuffed
You see a spike of failed sign-ins in the auth logs, customers locked out of their own accounts, or an SMS bill for codes nobody asked for. The reason sits in control 6’s row: repeated automated attempts can take over accounts or swamp the services that send codes and reset links. The nearest number I have is broader than login: 13 of the 21 apps had no rate limiting on their most expensive endpoint, in the same audits. That figure does not say which endpoint it was, so read it as limits missing in general, not a count of unprotected login forms. The brute force login protection page goes deeper.
A user signs out and the old session keeps working
Someone changes their password after a scare, or loses a laptop and signs out from another device, and a session somebody else holds keeps working. Control 2’s row names this plainly: an old session can outlive the owner’s attempt to lock it down. Control 9’s row names the other half: people need a way to cut off lost devices and sessions they do not recognize. I have no audit number for this one. The JWT security page and the active session management page go deeper; the tests for both sit under controls 2 and 9 below.
The 11 controls, one by one
Each control below says what it covers, the test that proves it, and the page to read next.
1. Every authentication flow works, including the failure paths
Every way into an account and out of it is covered: sign-up, sign-in, sign-out, password reset, the email confirmation link and the OAuth return route, each checked and fixed where it breaks. The test: exercise successful, rejected, expired, and reused-token paths for each supported flow. A reset link that works twice, or an OAuth callback that accepts a stale state value, fails here. Each flow in more depth: the authentication best practices page; password rules come under NIST minimum password length, named above.
2. Sessions and tokens expire, refresh and revoke
Sessions end when they should: they expire, refresh on schedule, and stop working when the user signs out or changes their password. The test: confirm expired and revoked sessions cannot continue accessing protected resources.
On timeouts, OWASP’s Session Management Cheat Sheet ties the numbers to how critical the app and its data are: “Common idle timeouts ranges are 2-5 minutes for high-value applications and 15-30 minutes for low risk applications,” and for an app used by an office worker all day, “an appropriate absolute timeout range could be between 4 and 8 hours.”
On Supabase Auth, access tokens are “usually between 5 minutes and 1 hour” and refresh tokens “can only be used once.” Time-boxed sessions, an inactivity timeout and a single session per user are “only available on Pro Plans and up”; otherwise, “all sessions are active until the user signs out or performs some other action that terminates a session.” So on the free plan a session ends only through those other actions, such as signing out or changing the password. Supabase’s sign-out page adds a condition that matters for the test: “Access Tokens of revoked sessions remain valid until their expiry time, encoded in the exp claim.” On a default Supabase build, then, a revoked session’s requests are refused only once its access token expires, unless your server also checks the session itself. Record which of the two your test ran. Tokens between services are a separate topic: API authentication best practices. JWT security goes deeper on token claims.
3. Authorization is enforced on the server, every route
Every protected page, API route and server action checks permissions on the server, whatever the interface shows or hides. Of all the web application authorization best practices, this is the one I would never skip, because a missing check here is invisible in the interface. For a SaaS, the authorization best practices that matter most add one input to every decision: the workspace or tenant the row belongs to, read from the session and never from the request body. The test: call protected actions directly as unauthorized and underprivileged users; confirm rejection. Broken access control goes deeper on the patterns that fail this.
4. Data is isolated across every table
Row-level security, or equivalent scoping on the server, covers all tables, and any table meant to be readable by everyone gets explicit rules for intentionally public data instead of a missing policy. The test: run read and write tests as anonymous users, different roles, and separate tenants. On Supabase, a blocked request can come back as no rows rather than an error, and Supabase’s own RLS guide warns that “Matching no rows is not proof on its own,” so check that the row you targeted is intact. Policy patterns and pitfalls are in Supabase RLS best practices. Multi-tenant data isolation goes deeper on tenant design.
5. Admin actions are protected
Admin pages and admin operations accept only roles that are named explicitly and checked on the server, never a flag the client can set. The test: test administrative operations using both authorized and ordinary accounts. Run each admin action twice, once as an admin and once as an ordinary signed-in user, and keep both responses. The admin panel security checklist goes deeper.
6. Login abuse is rate-limited and recoverable
Sign-in, sign-up, reset and code endpoints have rate limits and brute-force protection, and a real user who trips them can still get back in. The test: simulate repeated attempts and verify limits, responses, and normal-user recovery. Supabase Auth limits by IP address: its token endpoint, which covers password sign-ins, defaults to 150 requests per 5 minutes and sign-up, recovery, magic link and OTP requests to 30 per 5 minutes, each with bursts up to 30 requests; the built-in email provider allows 2 emails per hour for the whole project, a limit you can configure when you use custom SMTP or the Send Email hook. In my reading, limits keyed to an IP address do not slow an attacker spread across many addresses, so per-account protection is still yours to add. Brute force login protection goes deeper.
7. The role model is written down and matches the backend
A one-page matrix lists every role and what each may do, so the code has something to be checked against. The test: compare the role matrix with tested backend permissions. Where the matrix and the backend disagree, the backend is what users get, so fix the code or change the matrix on purpose. For sample matrices, see the RBAC examples page.
8. Account deletion is complete
Deleting an account removes the user’s related records and stored files too, under retention rules that are written down. The test: delete a seeded account and inspect its related records, files, and recorded retention exceptions. The account deletion feature page covers the flow itself. Anything you keep on purpose, such as invoices, belongs in the retention exceptions with its reason.
9. Active sessions can be listed and killed everywhere
Users can see their active sessions and sign out of all of them at once. The test: create multiple sessions, revoke them, and confirm protected access stops. On Supabase, sessions live in the auth.sessions table, and a sign-out with the global scope, the default in the JavaScript library, terminates every active session for that user. The access-token condition under control 2 applies here too. What is active session management goes deeper.
10. Sensitive actions are audit-logged
Role changes, deletions and billing changes each write a record of who did what and when, and only the right people can read that record. The test: trigger the listed actions and verify accurate, access-controlled audit entries. Check the entry names the real actor, not a service account, and that an ordinary user cannot read the log. What to log and for how long is the subject of the audit logging best practices page.
11. Two-factor on every owner and admin account
Every owner and admin signs in with a second factor, in the application and on every provider dashboard behind it, with recovery codes stored in the owner’s vault. The test: attempt sign-in to each owner and admin account without the second factor and confirm it is refused. On Supabase Auth, a password sign-in is itself aal1, “verified using a conventional sign-in method such as email+password,” so it still returns a session; the second factor raises it to aal2. Read “refused” as the admin data and actions refused to that aal1 session, which is what a restrictive policy checking the aal claim does. Recovery codes are not stated in Supabase’s MFA docs, so plan where they come from. Implement two-factor authentication goes deeper.
Buying login instead of building it
Two questions decide whether you keep the login you have: what an identity provider is, and what the IAM and PAM vendors are selling.
What is IdP in IT: an identity provider, and when buying login beats building it
An identity provider, or IdP, is the service that stores accounts, checks sign-ins and issues the tokens your app trusts. A small SaaS on Supabase or Firebase Auth already uses one. My working rule: buying a separate provider is worth it when a customer asks for single sign-on or nobody on the team can maintain the login flows.
NIST’s definition of an identity provider is narrower and more formal: “The party in a federation transaction that creates an assertion for the subscriber and transmits the assertion to the RP,” the RP being your app. In login and access software, the IdP meaning is this one; elsewhere the same letters stand for unrelated things. IdP authentication means the provider checks the sign-in and your app trusts the token it hands back. An IdP login is the sign-in page the provider hosts, which your users see instead of a form you built. IdP integration, for a small SaaS, means the app trusts the provider’s tokens instead of keeping its own password table.
Examples of identity providers: Supabase Auth and Firebase Authentication come built into the backend, while Auth0, Clerk, WorkOS, Okta and Microsoft Entra ID are standalone cloud IdP services. Buying one of the standalone ones is what authentication as a service means: login sold on its own, apart from your database. None of this is a ranking. Every cell in the table below is my reading, not a vendor’s claim.
| Criterion | Keep the generated login | Move to a managed provider |
|---|---|---|
| Who maintains the flows | You, in your own code or your backend’s auth | The provider; you maintain the integration |
| A customer asks for SSO | You build it or add it later | Usually the reason you are switching |
| Where the user table lives | Your database, next to your data | The provider’s system, linked to yours by an id |
| Cost model | Part of the backend you already run | A second vendor bill, on that vendor’s pricing model |
| Lock-in | Tied to your backend | Tied to the provider; switching IdP providers later means moving every user |
| What the 11 controls still ask of you | All 11 | Authorization, data isolation, the role model, deletion and the audit log stay yours |
My working rule has two halves: keep the generated login when it is a managed backend’s auth and all 11 controls pass their tests; move to a separate provider on the day a customer asks for SSO, or when nobody left on the team can own the flows. If that day has come, the page for when a customer asked you to add SSO covers the request itself, and OpenID Connect vs SAML covers the protocol choice. Whichever way you go, keep security questions out of account recovery; examples of security questions covers why.
IAM solutions and PAM: what the vendors sell, and what a small SaaS needs
An IAM solution manages which people in a company can reach which systems, and a PAM solution guards the few accounts with administrative power. Both are built for company-wide IT. A small SaaS needs the same ideas at its own size: named admin accounts, a second factor on each, and a log of what they change.
NIST’s glossary files identity and access management under identity management: “the administration of individual identities within a system, such as a company, a network or even a country,” and “In enterprise IT, identity management is about establishing and managing the roles and access privileges of individual network users.” An IAM solution or IAM platform, in my reading, is what a company buys to run that for its staff across many systems at once.
For privileged access management, NIST’s glossary gives only the acronym, PAM, with no definition, so this line is my own. What PAM in cyber security covers is the small set of accounts that can change everything: database superusers, cloud root accounts, the admin role in your app. A privileged access management (PAM) solution puts extra control around those accounts, for companies that have many of them.
My working rule: the best identity management solution for a small SaaS is usually the auth its backend already has, plus the 11 controls above. The best practices for identity and access management that survive at this size are few: named admin accounts rather than a shared login, a second factor on each (control 11), least privilege in the role model (control 7) and an audit log of what admins change (control 10). Of the identity frameworks, NIST SP 800-63 is the one worth knowing by name, since its 800-63B volume supplies the factor types above.
How to verify the whole area in an afternoon
Verifying this area takes 11 tests and, as my working estimate for a small app, one afternoon: read as a second account, call protected routes as the wrong role, reuse a revoked session, hammer the login, delete a seeded account, and sign in to an admin account without the second factor. Record each result with the date.
Run them against a staging copy with test accounts you created, never against real customers, in this order. Each item points back to its control; the exact test wording is under that control. For every item, write down the date, the request you sent and the response you got, including an empty result.
- 01 Second-account reads and writes: sign in as a second account and try to read and change rows owned by the first account (control 4). An empty result is not yet a pass; confirm the target row is unchanged.
- 02 Direct calls as the wrong user: call each protected route with no session and with a lower role (control 3).
- 03 Admin operations as an ordinary account: repeat every admin action from a normal user (control 5).
- 04 Revoked session reused: sign out, change the password, then replay the old session and note whether you waited out the access token (control 2).
- 05 Sessions on several devices: open sessions on two or more devices, revoke them all, confirm none still works (control 9).
- 06 Repeated attempts: hammer sign-in and reset, then confirm a real user can still get in (control 6).
- 07 Failure paths: run each flow with a wrong password, an expired link and a reused link (control 1).
- 08 Role matrix against the backend: walk the matrix row by row and compare what the server allows (control 7).
- 09 Seeded account deleted: delete it and look for leftover rows, files and exceptions (control 8).
- 10 Audited actions triggered: change a role, delete a record, change billing, then read the log as an admin and as a normal user (control 10).
- 11 Admin sign-in without the second factor: try each owner and admin account with the password alone (control 11).
When all eleven pass, the rest of the app still needs its own list, the full production readiness checklist, covering the other areas the same way.
Where the sprint stops
In the sprint, the app’s current framework and hosting setup are the starting point: the work happens inside the existing codebase, and components are refactored or replaced only where the production work requires it. Formal third-party certifications and independent audit opinions are separate from the sprint deliverables. Third-party hosting, service subscriptions and API consumption remain in the client’s own accounts, and required service costs are explained before anything is enabled.
Where the sprint does this
Area 1 of the Production Hardening Sprint is these 11 controls, 11 of its 123 deliverables. We deliver each one as described under the 11 controls above and check it with the test quoted there. Every result goes into the production readiness report, which accounts for all 123 IDs, keeps failures visible until resolved and explains genuine non-applicable items. The full list is area 1 of the published scope.
Common questions about authentication for a SaaS
What are the four types of authentication?
NIST names three authentication factor types, not four: knowing a secret, holding a device, and being the person a biometric matches. Lists of four or five add location or behavior factors, or count methods. For a small SaaS the methods table above has five: passwords, magic links, provider sign-in through Google or GitHub, passkeys, and app or SMS second factors.
Can you give me an example of authentication?
Signing in with a password and then typing a code from an authenticator app is authentication with two factor types in one sign-in: the password is something you know, and the phone holding the app is something you have.
What is basic auth vs OAuth?
Basic auth sends a user-id and password with the request, encoded in Base64 rather than encrypted, which is why RFC 7617 does not consider it secure without something like TLS around it. OAuth works the other way: instead of the resource owner’s credentials, the app obtains an access token from an authorization server and uses that. Which one fits an API is covered on the API authentication best practices page.
What is IdP vs SSO?
The IdP is the service that checks who you are and vouches for you to the app. Single sign-on is what that makes possible: NIST describes it as a process where “one account and its authenticators are used to access multiple applications in a seamless manner, generally implemented with a federation protocol.” An app can use an IdP without offering single sign-on across other apps.
What does IdP stand for?
In IT, IdP stands for identity provider, the party that creates an assertion about a signed-in user and sends it to the app. Outside IT the letters mean other things, so check the context.
The checks in this guide show you where the app is open. The sprint below closes those gaps, tests the result and writes the evidence down.
Built it with AI. Now it has to hold up for real customers.
The Production Hardening Sprint takes the app you already have and builds the production foundation underneath it. Authentication and access rules, payments that stay consistent, error handling, monitoring, backups, automated tests and a documented handover. Our engineers work inside your existing codebase for ten working days. All 123 deliverables are included, and you get the evidence for each one.
See the Production Hardening Sprint →
$2,500 fixed price · 10 working days · One codebase