How do you test an AI-built app before coworkers use it?
A two-account test for the access mistakes a working demo cannot reveal. Includes a result sheet and a prompt for your coding agent.
Your coding agent built an app that works. You signed in, added a request, edited it, and saw the right result. Now you want six coworkers to use it.
Before sending invitations, answer a different question: what happens when a second person uses the same app? A request tracker can work perfectly for its maker while letting every signed-in person open everyone else's requests. A hidden Approve button can look correct while the server accepts the same action from anyone.
You can catch those failures with two test accounts and a few disposable records. This guide works with any host that can give two people separate sessions. We make Spryloom, which publishes agent-built apps behind sign-in; the checks apply whether you host with us or elsewhere.
Prepare two people and one record
Use accounts you control, with different email addresses. Give them different roles or data ownership where the app allows it:
| Test person | Example role | Should be able to do |
|---|---|---|
| A | requester | Create and edit A's own purchase request |
| B | requester | Create and edit B's own purchase request; no access to A's private request |
| C, optional | approver | See requests assigned for approval and approve them |
Use fake names, amounts and attachments. Give A a distinctive record such as “Blue notebook, $17, request 4821.” Give B a different one. Keep each account in its own browser profile or private window. A second tab in the same profile may share the same session, so it does not prove separation.
Write down what the app should allow before you test. If all team members are supposed to see all requests, reading A's request as B is expected; editing or approving it may still be forbidden. The rule comes from the workflow, not from this article.
Run the five checks
1. Start without signing in
Open the app's address in a fresh private window. Try the main page and a direct record URL copied from A's session. Both should lead to sign-in or a refusal before private data appears. If the app has an API, ask your agent to check its unauthenticated data routes too. A protected homepage says nothing about an unprotected /api/requests/4821.
Record the exact URL and result. A redirect, 401, 403 or 404 can each be appropriate; the invariant is that no private data is returned and no change is made.
2. Let B open A's direct record URL
Sign in as A, open the distinctive record, and copy its address. Sign in as B in the other browser profile and paste the same address. Then have your agent repeat the underlying data request using B's session in a controlled test environment.
For a private record, B should see a refusal or a neutral “not found” result. The response must not include A's title, amount or attached file, even if the page visually hides them. Change the record identifier in a URL or request and test another fake record too. OWASP calls this class of failure an insecure direct object reference and recommends testing with at least two users and different owned objects. OWASP testing guide
3. Try the forbidden action, not just the screen
While signed in as B, try to edit A's record. If approval is reserved for C, try to approve as A or B. A hidden button is useful interface design, but the server must refuse the request itself. The test passes only when the record is unchanged after you refresh as A or C.
Ask the agent to test the action through the same API route the browser uses. The agent should report the response and query the record afterwards. OWASP's authorization guidance says permissions should be checked on every request, including requests made outside the normal UI. OWASP authorization guidance
4. Remove B's access while B is signed in
Leave B's session open. As the owner, remove B's access. In B's still-open window, refresh the app and retry a direct record URL and a write action. Record whether access ends immediately or after a documented session lifetime. If the product promises immediate revocation, a successful request is a failed test.
Removing someone from an invitation list is not enough if an old session still works. Session expiry and invalidation are server-side behaviors; closing a browser tab does not establish either one. OWASP session guidance
5. Check where the data went
Use A's session to add or edit a fake record. Look at the list as B and C. Does the change appear only where the rules say it should? Ask your agent to inspect responses from list endpoints, exports, notification emails and scheduled jobs, not just the detail page. A record can be protected at /requests/4821 yet leak through a search result or a Monday summary.
If the app emails anyone, trigger one test message to an inbox you control. Check that it reached the right recipient and that its body contains only information that recipient may see. If the app cannot run the job on demand, say that this part remains untested.
Keep a result sheet
Do not accept “all tests passed” without the evidence that says what was tested. Fill one row for each rule:
| Rule | Who tested it | URL or action | Expected | Observed | Pass? |
|---|---|---|---|---|---|
| Private data needs sign-in | anonymous | A's record URL | No record data | ||
| A's record is private from B | B | A's record URL and data request | No record data | ||
| B cannot change A's record | B | edit request | Refused; A's record unchanged | ||
| Only C approves | A and B | approve request | Refused; status unchanged | ||
| Revocation takes effect | B, session left open | read and write after removal | Refused within promised time | ||
| Email respects permissions | test inboxes | scheduled or manual message | Right recipient and content |
Mark a row untested if you cannot run it. That is a useful result: it tells you what still stands between the demo and a team dependency.
In our own last-mile benchmark, we verified that the live apps required sign-in and resisted forged identity headers. We did not run the live cross-user read and approval checks for all three routes; those had been checked locally. We say so in the published results. A working end-to-end demo gave us evidence of the path to a coworker, but it did not establish every permission rule in production. That distinction is why this test matters.
Give your agent a precise testing job
Copy this into the coding agent that has the app's source. Replace the bracketed text with your workflow:
Test access control for this app using disposable records and two separate accounts, A and B. A should be able to [describe A's allowed actions]. B should be able to [describe B's allowed actions]. B must not [describe forbidden read or write]. If there is an approver role, only that role may [approval action]. First list the pages, API routes, exports, jobs and emails that can expose or change these records. Test anonymous access, B reading A's record by direct ID, B attempting the forbidden write, and access after B is removed while its session remains open. Check the stored record after each denied write. Use only test accounts and fake data. Return a table with the request or action, expected result, observed status and body summary, data state afterwards, and pass, fail or untested. Show me failures before changing code.
The agent can automate much of this if the test environment supports separate sessions. It may still need you to sign in to each test account or arrange test identities. Do not paste a real session cookie into a chat or a public issue to make the test easier.
Decide what the result means
A failed read or write check is a reason to fix the app before putting real team data in it. A passed check applies to the routes and roles you actually tested, at the version you tested. Add this matrix to the app's release notes and run it again after a change to roles, routes or data sharing.
If you use Spryloom, its sign-in gate controls who may reach the app and passes the signed-in identity to it. The app still decides whether B may see A's record or approve a request. On another host, you will need to establish both the sign-in gate and the app's own record rules. Either way, the second account tells you more than the maker's successful demo ever could.