Define roles that reflect your business model: user, premium_user, moderator, admin, superadmin. Assign each API function a minimum required role. Enforce the check in the API — not in the frontend, not in the mobile app.
The check must happen in the server-side code that processes the request, before the business logic runs:
1. Extract the user’s role from the authenticated token (JWT claim, session, database lookup)
2. Compare it against the required role for this endpoint + HTTP method
3. If the user’s role doesn’t meet the requirement: return 403 immediately
4. If it does: proceed to the handler
Bumble’s premium endpoints called Bumble Boost features — a specific subscription tier. The role check for those endpoints should have been: if user.subscription != ‘boost’: return 403. Instead there was no such check. The UI enforced it by not showing the button. The API didn’t.
Store the user’s role(s) in the JWT payload as a claim (e.g., "roles": ["premium_user"]). Read it on every request. Never derive the role from the token’s account ID alone — look up the current role from the database on sensitive operations to catch role changes mid-session.
Ask your team to list the roles your API recognizes — then ask whether every admin or elevated function is explicitly restricted to those roles, or whether it is just hidden from the user interface.