[Web/API] Section 2 — Authentication, Authorization, BOLA, BFLA, Mass Assignment

 

1. Authentication vs Authorization

Authentication and authorization are different checks.

Authentication answers:

Who is the user?

Examples:

  • Is the token valid?

  • Is the session active?

  • Is the user logged in?

  • Is the JWT signature valid?

  • Is the token expired or not?

Authorization answers:

What is this user allowed to access or perform?

Examples:

  • Can this user access this invoice?

  • Can this user view this device?

  • Can this user delete this order?

  • Can this user export all reports?

  • Can this user assign admin role?

Memory line:

Authentication proves identity. Authorization checks permission.

A valid token only proves that the user is logged in. It does not automatically mean the user can access every object or function.


2. 401 vs 403

CodeMeaningExample
401Not authenticated   No token, invalid token, expired session
403Authenticated but not authorized    Valid user tries admin action

Memory:

401 = Who are you?
403 = I know who you are, but you are not allowed.

Example:

GET /api/admin/users

No token              → 401
Normal user token     → 403
Admin token           → 200

3. BOLA / IDOR

BOLA means Broken Object Level Authorization.
In traditional web testing, this is commonly called IDOR, Insecure Direct Object Reference.

This happens when a user can access another user’s object by changing an object ID.

Example:

GET /api/invoices/1001   → own invoice
GET /api/invoices/1002   → another user’s invoice

The user is authenticated, but the backend does not check whether the requested object belongs to that user.

Root cause:

Backend validates login but does not enforce object ownership or permission.

Fix:

Server should derive user identity from trusted session/token and verify object ownership, tenant, role, or permission before returning data.

Example backend logic:

invoice_id = requested invoice
logged_in_user_id = from trusted token/session

Allow only if:
invoice.owner_user_id == logged_in_user_id

Memory:

Wrong object ID = BOLA / IDOR.


4. Tenant-Level Authorization

In a SaaS or product environment, the same application may be used by multiple companies or customers.

Example:

Company A = tenant 100
Company B = tenant 200
Company C = tenant 300

Each company’s data must remain separate.

Tenant-level authorization prevents one company from accessing another company’s data.

Example issue:

GET /api/companies/100/users   → allowed
GET /api/companies/200/users   → should be blocked

If a user from company 100 can access company 200 data, this is:

Cross-tenant BOLA / tenant-level authorization failure.

Fix:

requested_company_id == logged_in_user.tenant_id

or:

object.tenant_id == logged_in_user.tenant_id

Memory:

Tenant check = company/customer boundary.


5. Same Company, Different User

Tenant check alone is not always enough.

Two users may belong to the same company, but they may not have the same permissions.

Example:

Varun  → tenant ZF → normal user
Amit   → tenant ZF → normal user
Admin  → tenant ZF → admin

A normal user may only see their own records.
A manager may see team records.
An admin may see company-wide records.

So backend authorization may need multiple layers:

1. Is the user authenticated?
2. Is the object in the same tenant/company?
3. Is the user the owner?
4. Is the user a manager/admin?
5. Does the user have the required permission?

Memory:

Tenant check prevents company-to-company access.
Ownership/role check prevents user-to-user abuse inside the same company.


6. BFLA — Broken Function Level Authorization

BFLA happens when a user can access a function or endpoint that their role should not be allowed to use.

Example:

GET /api/reports/my-report       → allowed for normal user
GET /api/reports/export-all      → should be admin/reporting role only

If a normal user can call export-all, it is BFLA.

Another example:

GET /api/admin/users
Authorization: Bearer <normal_user_token>

If a normal user receives the full user list, the backend is missing role/permission checks.

Root cause:

Backend checks that user is logged in, but does not check whether the user has permission to use that function.

Fix:

1. Validate token/session.
2. Extract user role/permissions from trusted identity.
3. Check required permission for the function.
4. If permission missing, return 403.

Memory:

BFLA = wrong function/action access.


7. BOLA vs BFLA

ScenarioClassification
User changes invoice ID and accesses another invoiceBOLA / IDOR
User changes company ID and accesses another tenantTenant-level BOLA
Normal user accesses /admin/usersBFLA
Normal user calls /reports/export-allBFLA
Normal user changes GET to DELETE on same objectMethod-level authorization / BFLA
User adds "role": "admin" in request bodyMass assignment
API returns password hash/MFA secret/internal notesExcessive data exposure

Memory:

BOLA = wrong object.
BFLA = wrong function.
Mass assignment = dangerous field accepted.
Excessive data exposure = dangerous field leaked.


8. Method-Level Authorization

Same endpoint path can behave differently based on HTTP method.

Example:

GET    /api/orders/5001   → view order
DELETE /api/orders/5001   → delete order

A normal user may be allowed to view their order but not delete it.

If the backend allows DELETE without checking permission, this is a method-level authorization issue, often classified under BFLA.

Root cause:

Backend does not enforce authorization per method/action.

Fix:

GET /orders/{id}     → view permission
PATCH /orders/{id}   → edit permission
DELETE /orders/{id}  → delete/admin permission

Memory:

Same object, wrong action = method-level authorization issue.


9. Mass Assignment / Broken Object Property Level Authorization

Mass assignment happens when the backend blindly accepts extra fields from the request body.

Example:

PATCH /api/users/123

{
  "name": "Varun",
  "phone": "9999999999",
  "role": "admin"
}

The profile update function may be valid, but the user should not be allowed to update sensitive fields like role.

Root cause:

Backend directly maps client-supplied fields to database object without field-level allowlisting.

Impact:

Privilege escalation if role, permissions, is_admin, tenant_id, or account_status can be modified.

Fix:

Use server-side allowlisting.

Allowed fields for normal user:

name
phone
profile_picture
address

Blocked/protected fields:

role
is_admin
permissions
tenant_id
account_status
credit_balance
mfa_secret

Memory:

Extra dangerous field accepted = mass assignment.


10. Invite User as Admin Scenario

Example:

POST /api/users/invite

{
  "email": "newuser@test.com",
  "role": "admin"
}

If a normal user can invite another user as admin, this is:

Mass assignment / property-level authorization failure leading to privilege escalation.

It may also involve missing permission checks around role assignment.

Fix should check both:

1. Can this user invite users?
2. Can this user assign the requested role?

Example policy:

Normal user → cannot invite, or can invite only basic user
Manager → can invite normal users
Admin → can invite admin users

Memory:

Dangerous role in request body = property-level authorization issue.


11. Excessive Data Exposure

Excessive data exposure happens when the API returns sensitive fields that the user should not see.

Example:

GET /api/users/me

Bad response:

{
  "id": "123",
  "name": "Varun",
  "email": "varun@test.com",
  "role": "user",
  "salary": "50000",
  "password_hash": "$2b$...",
  "mfa_secret": "ABCDEF",
  "internal_notes": "High risk customer"
}

The user may be allowed to call /users/me, but the response should not include sensitive/internal fields.

Root cause:

Backend returns full database object instead of response-specific allowlisted fields.

Fix:

Use response filtering / DTO / serializer allowlisting.

Safe response:

{
  "id": "123",
  "name": "Varun",
  "email": "varun@test.com"
}

Memory:

Mass assignment = dangerous field accepted in request.
Excessive data exposure = dangerous field leaked in response.


12. Senior Testing Approach

For access control testing, use at least two users or two tenants.

Basic test flow:

1. Login as User A.
2. Capture valid request in Burp.
3. Identify object ID, tenant ID, method, body fields, and function.
4. Replace object ID with User B object.
5. Replace tenant/company ID with another tenant.
6. Try privileged endpoint with normal user token.
7. Try dangerous methods like DELETE/PATCH.
8. Add sensitive body fields like role/is_admin/tenant_id.
9. Compare response: 200 vs 401 vs 403 vs 404.
10. Confirm impact and expected secure behavior.

Expected secure behavior:

Wrong object      → 403 or 404
Wrong tenant      → 403 or 404
Wrong function    → 403
Dangerous field   → reject or ignore
Sensitive response fields → not returned

13. Finding Report Structure

For any API authorization issue, write findings like this:

Vulnerability:
Affected endpoint:
User/role used:
What was changed:
Observed result:
Impact:
Root cause:
Recommended fix:
Expected secure behavior:
Retest steps:

Example:

Vulnerability: Tenant-level BOLA / IDOR

Endpoint:
GET /api/v1/vehicles/{vehicle_id}/driver-history

What was changed:
Changed vehicle ID from Company A vehicle to Company B vehicle using Company A token.

Observed result:
API returned Company B vehicle driver history.

Impact:
Cross-tenant exposure of sensitive fleet and driver data.

Root cause:
Backend fetches vehicle history by vehicle ID without validating tenant ownership.

Fix:
Derive tenant ID from trusted token/session and enforce vehicle.tenant_id == logged_in_user.tenant_id, plus required permission like view_driver_history.

Expected behavior:
Company A user should receive 403 or 404 for Company B vehicle IDs.

Retest:
Use two test tenants and confirm cross-tenant vehicle IDs are blocked after the fix.

14. Best Interview Lines

Use these lines in interview:

A valid token proves the user is authenticated, but it does not prove they are authorized for every object or action.

For BOLA, I check whether the requested object belongs to the authenticated user, tenant, or allowed permission scope.

For BFLA, I check whether the user’s role is allowed to access that specific function or endpoint.

For mass assignment, I check whether the backend accepts sensitive request-body properties like role, is_admin, permissions, or tenant_id.

For excessive data exposure, I check whether the API response leaks fields that the UI does not need or the user should not see.

In a multi-tenant SaaS product, tenant boundary enforcement is critical because one customer must never access another customer’s data.


15. Final Memory Pack

Authn = who are you?
Authz = what can you access/do?

401 = not authenticated.
403 = authenticated but not authorized.

BOLA / IDOR = wrong object.
Tenant-level BOLA = wrong company/customer object.
BFLA = wrong function.
Method-level authz = wrong HTTP action.
Mass assignment = dangerous field accepted in request body.
Excessive data exposure = dangerous field leaked in response.

Tenant check = company/customer boundary.
Ownership check = user/object boundary.
Role/permission check = action/function boundary.

Valid token is not enough.
Every object and function needs server-side authorization.

Never trust object IDs, tenant IDs, role, or permissions from the client.
Use trusted session/token context and enforce backend checks.

Comments