HOW TO TEST

How to Test Role-Based Access Control.

Security & Access A complete testing guide for RBAC: role definitions, admin/user/guest/read-only access, page and feature restrictions, data-level permissions, API authorization, direct-URL access, role changes, disabled users, and audit logging.

12
scenarios
9
test cases
15 min
read
intermediate-to-advanced5–8 hours (full suite); 1–2 hours (smoke pass covering the critical role-crossing boundary checks at API level) testingQA engineersSDETsSecurity engineers

Role-based access control is the boundary that separates data between users, protects administrative functions, and enforces business rules about who can do what. A single RBAC flaw — an API endpoint missing an authorization check, a frontend route guard not enforced server-side, a role assignment that survives account deactivation — can expose every user's data to every other user. This guide covers the full RBAC surface: verifying role definitions, enforcing page/feature/action restrictions per role, testing data-level permission scoping (not just feature flags), API authorization for every sensitive endpoint, direct-URL access bypasses, role change propagation, disabled-user access, and audit log completeness. All test cases are written for a Cypress/Playwright engineer who understands that frontend route guards are cosmetic — only server-side enforcement counts.

Risks

API endpoints missing authorization checks

Frontend route guards prevent navigation to restricted pages, but direct API calls bypass them entirely. Any endpoint that performs a sensitive operation (delete, update, export) without verifying the requester's role exposes that operation to every authenticated user.

Horizontal privilege escalation via IDOR

A user who knows (or guesses) another user's resource ID can access or modify it if the API does not verify that the requesting user owns or has permission to access that specific record. BOLA (Broken Object Level Authorization) is the most common API security flaw.

Vertical privilege escalation via role parameter manipulation

If the role is sent by the client in the request body or JWT claims and the server trusts it without re-verifying against the database, an attacker can self-promote to admin by modifying the request.

Role change not immediately propagated

If a user's role is changed (demoted from admin) but their existing JWT or session remains valid and is not re-checked against the current role on each request, the demoted user retains admin access until their token expires.

Disabled accounts retaining API access

Disabling a user in the admin panel revokes UI access, but if the backend does not check the account's active status on every API request, the user can continue making API calls with their existing token indefinitely.

Data scoping failure in multi-tenant environments

In multi-tenant applications, API queries that filter by userId but not by tenantId expose data across tenant boundaries. A low-privilege user in Tenant A should never see any data from Tenant B.

Audit logs missing or forgeable

Without an immutable audit trail of who performed which sensitive operation (and when), forensic investigation after a breach is impossible, and regulatory compliance (SOC 2, GDPR, HIPAA) requirements cannot be met.

Test Scenarios

Admin role can access all pages, features, and data

CriticalfunctionalFully automated

Authenticate as an admin. Assert all pages load without 403, all management features are visible, and all API endpoints return authorised responses.

Standard user cannot access admin-only pages or API endpoints

CriticalsecurityFully automated

Authenticate as a standard user. Assert admin pages return 403 in the UI. Assert direct API calls to admin endpoints return 403. Assert no admin-only UI elements are rendered.

Guest/read-only role cannot perform write operations

CriticalsecurityFully automated

Authenticate as a guest or read-only user. Assert create, update, and delete operations are blocked at both the UI (buttons hidden or disabled) and the API (403 returned for POST/PUT/DELETE requests).

Unauthenticated requests to protected endpoints return 401

CriticalsecurityFully automated

Send API requests without any authentication token to every sensitive endpoint. Assert HTTP 401 Unauthorized is returned — not 200, not 403.

User cannot access another user's resources via ID

CriticalsecurityFully automated

User A owns resource-123. User B knows the ID. As User B: GET /api/resources/resource-123. Assert 403 or 404 — not the resource data. Test for read, update, and delete.

Direct navigation to a restricted URL is blocked server-side

CriticalsecurityFully automated

Navigate directly to /admin/users as a standard user (not via the UI navigation). Assert the page returns 403 or redirects to an unauthorized page — not a blank/partially-rendered admin page.

Role demotion is enforced on the next API request

CriticalsecurityFully automated

Authenticate as admin (capture the token). Demote the user from admin to a standard role via the admin panel. Immediately use the same token to call an admin-only API endpoint. Assert 403 is returned.

Disabled user's token is rejected on all API endpoints

CriticalsecurityFully automated

Authenticate as a user (capture the token). Disable the account via admin. Use the captured token to make an API call. Assert 401 or 403 — not 200.

User can only see their own data in list endpoints

CriticalsecurityFully automated

User A creates 5 resources. User B creates 3. As User B: GET /api/resources. Assert exactly 3 resources are returned — none of User A's. As admin: assert all 8 are visible.

Sensitive operations are recorded in the audit log

HighfunctionalFully automated

As admin: create a user, delete a resource, and change a role. Assert each action appears in the audit log with: actor (admin user ID), action, target (affected resource/user), and timestamp.

UI elements for restricted features are not rendered for lower-privilege roles

HighsecurityFully automated

Authenticate as a standard user. Assert admin-only buttons (delete all, export all, manage roles) are not present in the DOM — not just hidden via CSS, but absent from the HTML.

Modifying the role claim in a JWT is rejected

CriticalsecurityFully automated

Decode a standard user's JWT, change the role claim to 'admin', re-sign with a different or invalid secret, and call an admin API endpoint. Assert 401 (invalid signature) is returned.

Detailed Test Cases

Preconditions

  • List of all admin API endpoints documented (e.g. GET /api/admin/users, DELETE /api/admin/users/:id, POST /api/admin/roles)
  • Standard user authenticated; token captured

Steps

  1. 1.For each admin endpoint in the list:
  2. 2.Send the request using the standard user's auth token
  3. 3.Assert HTTP 403 Forbidden
  4. 4.Assert response body does not contain any admin data
  5. 5.Assert response body does not leak admin route structure (no 'you need admin role to access /api/admin/...')

Expected result

Every admin endpoint returns 403 for a standard user; no data or route information leaked.

Evaluation criteria

  • HTTP status 403 — not 200 with empty data, not 401
  • Response body must not contain any records from the admin resource
  • No stack trace or internal path disclosed in the error response

Edge Cases

User with multiple roles — most permissive wins?

Some systems assign multiple roles to a user. Ensure the permission model is explicit: does the user get the union of all roles' permissions, or only the most restrictive? The behaviour must be documented and enforced consistently.

Role assignment race condition

Two admins simultaneously assign conflicting roles (one promotes to admin, one demotes to read-only). The final role state must be deterministic — last-write-wins with a timestamp, not arbitrary based on query arrival order.

Accessing a resource that was shared with a deleted user

If User B was granted access to User A's resource and User B's account is deleted, what happens to that grant? The grant record must be cleaned up — otherwise a re-registered account using the same email gets inherited access.

JWT not re-validated on role change when using long-lived tokens

With JWT expiry set to 24 hours, a user whose role was changed has 23:59 of continued access at the old role level. Server-side role checks (comparing the role claim against the current DB value on each request) eliminate this window.

Read-only role can access data export endpoint

A bulk CSV export endpoint that bypasses the normal data-scoping query can expose all records to any authenticated user, not just the user's own data — particularly dangerous for read-only service accounts.

Permission check on creation endpoint does not scope the parent resource

POST /api/projects/{projectId}/tasks — the endpoint checks that the user can create tasks (role permission) but does not verify that the user has access to {projectId}. Any authenticated user can add tasks to any project by guessing the project ID.

Super-admin role not tested separately from admin

Systems with super-admin and admin roles often have subtle differences in which operations each can perform. If both roles are treated as 'admin' in tests, the super-admin-only operations are never verified.

SSRF via admin-only URL fetch feature

An admin feature that fetches a URL (screenshot, webhook test) can be exploited via SSRF if it does not restrict internal IP ranges. A compromised admin account could use it to probe internal services.

Automation Ideas

Role-endpoint permission matrix test

Define a matrix of {role, endpoint, method, expectedStatus}. Drive every combination through the API in a parameterised test. This makes permission regressions immediately visible as a row in a failing test table.

Tools: playwright, postman, rest-assured

IDOR sweep across all resource endpoints

Create resources for User A, capture all IDs, then authenticate as User B and attempt GET/PUT/DELETE for each ID. Assert 403 or 404 for every attempt. Run as a security regression on every release.

Tools: playwright, cypress

Role demotion propagation test

Capture an admin token, demote the user via the admin API, then immediately replay the admin API call with the old token. Assert 403. Automatable as a pair of sequential API calls with a < 1 s gap.

Tools: playwright, postman

JWT signature tampering test

Use Node.js (or Python) in the test runner to decode the JWT, modify the role claim, and re-encode without the correct signing key. Assert 401. Integrate as a security smoke test in CI.

Tools: playwright, cypress

DOM accessibility and role-element audit

For each user role, load the main pages and assert that role-specific DOM elements are either present or absent using specific data-testid selectors. Combine with axe-core for a full accessibility check.

Tools: playwright, axe-core

Audit log completeness assertion

After each sensitive operation (delete, role change, export), query the audit log API and assert the entry exists with all required fields. Run as a contract test to catch regressions in audit coverage.

Tools: playwright, postman

Common Bugs

Authorization check on the wrong property

The API checks if the requesting user is the owner of the resource using resource.creatorId === userId, but the resource also has a separate ownerId field. Resources where the owner differs from the creator are accessible to any user.

Impact: Silent IDOR for all resources where creatorId ≠ ownerId.

Role stored in a client-accessible cookie and trusted by the server

The user's role is stored in a non-HttpOnly cookie. JavaScript can read and modify it. If the server reads the role from the cookie without re-validating against the database, the user can self-promote.

Frontend route guard fires after the component renders

The route guard is implemented as a useEffect hook that runs after the initial render. Admin data is briefly visible before the guard fires and redirects — a flash of unauthorised content that can be captured by a screenshot.

Deleted user's API key still works

Disabling or deleting a user account does not revoke their API keys. Long-lived API keys continue to authenticate requests indefinitely, bypassing the account disable entirely.

List endpoint returns all records sorted by ID — zero data scoping

GET /api/resources returns all records in the database because the WHERE clause was forgotten during a refactor. Every authenticated user sees every other user's data.

Permission check missing on bulk delete endpoint

DELETE /api/resources correctly checks ownership per resource ID, but DELETE /api/resources?ids=1,2,3 (bulk delete) does not check ownership — any user can delete any set of resources by passing their IDs in the query.

CORS allows all origins on admin API

The admin API returns Access-Control-Allow-Origin: * instead of restricting to trusted origins. A malicious page open in the admin's browser can make cross-origin API calls to the admin endpoints using the admin's browser session.

Impact: Any website the admin visits can silently exfiltrate data or perform admin operations.

Useful Tools

Playwright

End-to-end RBAC tests, role-switching between sessions, DOM element absence assertions, and JWT tampering via request interception.

Postman

API permission matrix testing — parameterised collections per role, environment-switching for auth tokens.

Burp Suite

Intercept and replay requests with modified role claims, headers, and resource IDs. Authorisation scanner for IDOR detection.

OWASP ZAP

Active scan for BOLA/IDOR, missing authorization headers, and SSRF in admin endpoints.

axe-core

Verify that role-restricted UI elements have appropriate aria-hidden or are removed from the DOM, not just visually hidden.

REST Assured

Build the role-endpoint permission matrix as a parameterised JUnit test — readable, data-driven, and CI-friendly.