All posts
No-Code & Tools

How to Test Authorization in an AI-Built App Before Real Users Find the Gaps

An app can authenticate every user correctly and still let one customer read another customer's records. Test authorization as a matrix of users, resources and actions before production.

Elvis Onunwa21 September 20267 min readLast updated: 21 September 2026
How to Test Authorization in an AI-Built App Before Real Users Find the Gaps

TL;DR

  • Authentication proves who a user is. Authorization decides what that user may read, create, change or delete.
  • Test at least two ordinary users plus every privileged role, and deliberately attempt cross-user and cross-role actions.
  • A hidden admin button is not authorization. The database or trusted server must reject the forbidden request even when the client sends it directly.
  • For Supabase apps, test both allow and deny cases for SELECT, INSERT, UPDATE and DELETE rather than assuming an RLS policy is correct because normal use works.
On this page⌄

An AI-built app can have a polished login screen, password reset and protected-looking dashboard while still having a serious access-control problem.

The mistake is simple: authentication is not authorization.

Authentication answers, “Who is this user?” Authorization answers, “May this user perform this action on this particular record?”

If you only test that users can sign in and see their dashboard, you have tested the first question. You have not proved the second.

The short version

Before real users arrive, create at least two ordinary accounts and every meaningful privileged role in the product. Then deliberately try actions that should fail.

For each important resource, test whether a user can:

  • read their own record
  • read another user’s record
  • create a record for themselves
  • create one for somebody else
  • update their own record
  • update somebody else’s
  • delete their own record
  • delete somebody else’s
  • call an admin or manager operation as an ordinary user

The important result is not that the interface hides the forbidden action. The underlying database or trusted server must reject it.

OWASP’s 2025 Top 10 keeps Broken Access Control at number one. Its guidance includes failures where users can view or edit another person’s account by changing an identifier, access APIs without the correct permission, or gain privileges beyond the role they were given.

Source: https://top10.owasp.org/2025/A01_2025-Broken_Access_Control/

Start with a permissions matrix, not random clicking

Authorization becomes easier to test when the product rules are written down.

Imagine a property app with Owner, Manager and Tenant roles. Instead of saying “managers have access,” define the actual decisions:

Resource/action Owner Manager Tenant
View property Allow Allow Relevant tenancy only
Edit property Allow Maybe Deny
View another tenant’s documents Allow if intended Maybe Deny
Record payment Allow Allow if delegated Deny
Change ownership Allow Deny Deny

That table is more useful than a vague role name because it gives you test cases.

AI coding tools are good at generating screens and CRUD flows. They cannot infer every business boundary correctly unless those boundaries are explicit.

Test horizontal access: user A versus user B

One of the highest-value tests is also one of the simplest.

Create two ordinary users, A and B. Give each user a record that belongs only to them. Then sign in as A and try to access B’s record.

Do not stop at the visible interface. Try the underlying request path the application itself uses. If a record URL or API call contains an ID, changing that ID must not grant access.

OWASP describes this class of failure as insecure direct object reference or broken object-level authorization: an application exposes an object identifier but fails to verify that the requesting user is allowed to access that object.

Source: https://wstg.owasp.org/latest/4-Web_Application_Security_Testing/12-API_Testing/02-API_Broken_Object_Level_Authorization/

A UUID that is difficult to guess is not a permission system. The server still needs to check ownership or another valid access rule.

Test vertical access: ordinary user versus admin

The second direction is privilege escalation.

Sign in as an ordinary user and attempt operations reserved for a manager or administrator.

Examples include:

  • approving another user’s request
  • exporting all customers
  • changing a subscription or payment state
  • inviting staff
  • editing system settings
  • reading audit logs
  • accessing an admin-only API route

If the only protection is if (user.role === 'admin') in a React component, the product is not adequately protected. A user can bypass a hidden button and send the request directly.

The trusted enforcement point belongs on the server, database policy or another backend boundary that the client cannot rewrite.

For Supabase apps, prove RLS with allow and deny tests

Supabase Row Level Security is particularly useful for AI-built apps because authorization rules can be enforced close to the data.

But having RLS enabled is not the same as having correct RLS.

Current Supabase guidance says exposed tables should use RLS and recommends tests that assert allowed and denied behaviour for select, insert, update and delete. Supabase also provides database testing through its CLI.

Sources: https://supabase.com/docs/guides/database/postgres/row-level-security https://supabase.com/docs/guides/database/testing

For a customer-owned table, useful tests include:

  1. anonymous user cannot read private rows
  2. authenticated user A can read A’s row
  3. A cannot read B’s row
  4. A can update the fields A is supposed to control
  5. A cannot transfer ownership by changing user_id
  6. A cannot delete B’s row
  7. a privileged backend operation works only through the intended trusted path

That fifth test is easy to miss. A policy can correctly restrict which rows a user updates while still allowing them to change a protected ownership field if the write rule is incomplete.

Test the business state, not only the database table

Real authorization rules are often contextual.

A manager may be allowed to edit a tenancy while it is in draft but not after it has been closed. A customer may download a receipt only after the payment is verified. A team member may access a project only while their grant is active.

Those are not merely roles. They are role + resource + state decisions.

Write them as product rules first, then test them.

This is where product thinking matters in AI-assisted development. The hardest permission bugs are often not syntax errors. They come from a system implementing a technically valid rule that does not match the business rule.

Do not test authorization with a service-role client

Be careful when testing Supabase from privileged server code.

Supabase’s secret and legacy service-role keys bypass RLS and must never be exposed in the frontend. A test performed through a privileged client can therefore give you a misleading result about what an ordinary signed-in user can do.

Source: https://supabase.com/docs/guides/database/secure-data

Test ordinary-user behaviour using the same authentication context the real client uses. Keep privileged clients separate and use them only for operations that genuinely require server authority.

If you are unsure which Supabase keys belong in the browser, see Is the Supabase anon key safe to expose?.

Turn permission bugs into regression tests

When you find an access-control bug, do not fix it and rely on memory.

Add a test that reproduces the forbidden action and proves it remains forbidden.

For example:

  • user A cannot select user B’s invoice
  • tenant cannot update landlord-only fields
  • manager cannot transfer ownership
  • expired grant cannot read a document
  • anonymous visitor cannot call a private function

This converts a security lesson into executable product knowledge.

The same principle is covered more broadly in how to regression-test an AI-built app: important rules should survive the next AI-generated change, not just today’s release.

A green security scan is useful, but it is not the final answer

Automated scans can catch missing RLS, exposed configuration and known classes of weakness. They are valuable.

They cannot automatically know every intended relationship in your product.

A scanner may see a valid policy. Only your product rules can establish whether that policy should allow a manager to read every property, only assigned properties, or no tenant documents at all.

That is why the Lovable security scan guide separates configuration checks from business-authorization verification.

The release test I would require

Before shipping an AI-built app with private user data, roles or payments, I would want evidence for four things:

  1. Identity: the application reliably knows which user is making the request.
  2. Ownership: ordinary users cannot cross into another user’s resources.
  3. Privilege: higher-risk operations are enforced by a trusted backend boundary, not merely hidden in the UI.
  4. State: permissions still behave correctly as records move through real business states.

Then I would preserve the critical deny cases as automated tests.

That is a stronger security argument than “login works” or “the scan passed.”

If your AI-built MVP has reached the point where permissions, payments, roles and production data need a proper architecture review, see my MVP development service or contact me. The goal is not to replace AI-assisted development. It is to make sure the product rules survive contact with real users.

Frequently asked questions

Questions, answered.

What is the difference between authentication and authorization?

Authentication establishes identity. Authorization decides whether that identity may perform a specific action on a specific resource. A working login can coexist with broken access control.

How do I test Supabase RLS in an AI-built app?

Create realistic test users and verify both allowed and forbidden operations. Supabase recommends testing RLS policies and supports database tests through its CLI; its RLS guidance specifically calls for allow-and-deny assertions across operations.

Is hiding an admin page enough to secure it?

No. Client-side navigation and hidden buttons are user-interface controls, not security boundaries. The underlying database or server operation must independently reject unauthorized requests.

NEED HELP WITH THE BUILD?

Turn what you learned here into a clearer website or MVP.

Share the goal, current stage, and constraints. I’ll help you identify the smallest responsible next step.

Continue reading

Related notes.