API Authorization and Security
By the Syncfusion DevTutorials team · Last updated
Check on every request that the caller is allowed to do this: own the record, have the role, carry the scope.
Authorization answers one question on every request: Is this caller allowed to do this?
Authentication tells the API who is calling. Authorization decides what that caller is allowed to see or do.
A valid token proves the identity of a user, but it does not automatically grant access to every resource. The API must still check ownership, roles, and permissions before allowing an action.
Watch Asha Read Ravi's Order
The API below correctly checks that the caller has a valid token. Press Run.
Program.cs — a BOLA hole
What happens? Asha requests order 101. Order 101 belongs to Asha, so the API returns 200 OK. So far, everything looks correct.
Next, Asha changes the URL from /orders/101 to /orders/102. Order 102 belongs to Ravi. The API still returns 200 OK, and it exposes the order of Ravi. The token was valid. The API knew the caller was Asha. The problem is that the API never checked whether Asha was allowed to access order 102.
In simple words: authentication proves who the user is. Authorization checks whether they are allowed to access a specific resource.
TL;DR
- Authentication = Who are you?
- Authorization = What are you allowed to do?
- Missing or invalid credentials return
401 Unauthorized. - Ownership, role, or permission failures return
403 Forbidden, or404 Not Foundin some cases. - Check authorization on every request.
- Always verify ownership before returning or modifying data.
- Take ownership information from the token, not from the request body.
- Use roles and scopes to control access to features.
A Real-World Example
Imagine a hotel. At the front desk, the staff checks your identity and gives you a room key card. That is authentication.
The key card then controls which doors you can open. It opens your hotel room, the elevator, and the gym. It cannot open the rooms of other guests, staff-only rooms, or maintenance areas. Every door checks the card before opening.
Authorization works exactly the same way. A valid token identifies the user, but each endpoint must still decide whether access should be allowed.
Authentication verifies identity. Authorization checks ownership, roles, and permissions before access is granted.
What You Will Learn
In this lesson, you will learn:
- The difference between authentication and authorization.
- How ownership checks prevent data leaks.
- What Broken Object Level Authorization (BOLA) is.
- How roles control access to privileged actions.
- Why ownership should come from the token, not the request.
- How scopes restrict what a token can do.
Authentication vs Authorization
| Question | Check |
|---|---|
| Who is calling? | Authentication |
| Is the caller allowed to do this? | Authorization |
| Missing token? | 401 Unauthorized |
| Valid token, but not allowed? | 403 Forbidden or 404 Not Found |
Authentication always happens first. Authorization happens after the identity of the user is known.
Check Ownership on Every Record
The bug from the first example is called Broken Object Level Authorization (BOLA). BOLA happens when an API checks that a user is signed in, but does not check whether they own the specific resource that they asked for. It is one of the most common API security vulnerabilities.
The API must compare the owner of the resource with the user identified by the token.
The fix is straightforward:
- Read the user id from the token.
- Read the owner of the resource.
- Compare them.
- Allow access only if they match.
Program.cs — ownership check
Results:
No Token
The response is 401 Unauthorized with WWW-Authenticate: Bearer. The API does not know who the caller is.
Asha Requests Order 101
The response is 200 OK. The order belongs to Asha.
Asha Requests Order 102
The response is 404 Not Found. The order belongs to Ravi.
Why return 404 Not Found instead of 403 Forbidden? A 403 tells the caller that the resource exists. A 404 makes "not yours" and "does not exist" look exactly the same. This stops attackers from finding out which resource ids are valid.
Roles: Staff-Only Actions
Sometimes ownership is not enough. Certain actions should only be available to users with special roles. Examples are Administrator, Manager, and Support Staff.
In Brew & Bytes, refunds can only be processed by staff members.
Program.cs — admin-only refund
Customer Token
Authentication succeeds, and the user is known. However, the role is customer. The API returns 403 Forbidden.
Admin Token
The role is admin. The refund succeeds, and the API returns 200 OK.
Use a "deny by default" approach. Only users who are clearly allowed should get access. Everything else should be denied automatically.
Never Trust the Owner in the Request Body
A common mistake is allowing the caller to specify ownership information.
Example request: {"customerId": "customer-8", "item": "Latte"}
What if Asha sends the id of Ravi? If the API trusts the request body, Asha could create or change records that belong to Ravi. Instead, ownership must always come from the authenticated token.
Program.cs — owner from the token
Correct approach: Owner = token.sub. Not: Owner = request.customerId
Never trust user identity information that comes from request bodies, query strings, URLs, or form fields. Identity should always come from a validated token.
Scopes: Limit What a Token Can Do
Roles control broad access. Scopes control specific permissions.
Examples: orders:read, orders:write, payments:read, and payments:refund
Scopes allow the API to grant only the permissions that are required.
Program.cs — partner scopes
Example: the partner token contains the scope orders:read. The request GET /partner/orders succeeds. The request POST /partner/orders fails, because it requires the scope orders:write.
The API returns 403 Forbidden with WWW-Authenticate: Bearer error="insufficient_scope", scope="orders:write". The response clearly explains which permission is missing.
Authorization Policies in ASP.NET Core
Real applications often keep authorization rules in one place by using policies. Examples are StaffOnly, OrdersWrite, and ManagersOnly. Policies are easy to reuse across multiple endpoints.
Good candidates for policies are roles, claims, and scopes.
Ownership checks usually stay inside the endpoint logic, because each resource has a different owner. For example, order.CustomerId == currentUserId must be checked using the specific resource that is being accessed.
Browsers and CORS
Authorization protects your API. CORS solves a different problem. CORS tells browsers which websites may read responses from your API.
Examples: https://shop.brewandbytes.in and https://admin.brewandbytes.in
A browser may send a preflight request, OPTIONS /orders, before it sends the actual request. The API replies with the headers Access-Control-Allow-Origin, Access-Control-Allow-Methods, and Access-Control-Allow-Headers.
Program.cs — CORS for the web shop
Allowed Website
The response contains the header Access-Control-Allow-Origin. The browser allows the JavaScript code to read the response.
Unapproved Website
The response does not contain the CORS permission headers. The browser blocks access.
CORS is not a security system for your API. It only controls what browser-based JavaScript can read. Tools such as curl, Postman, mobile apps, and server-to-server calls ignore CORS completely. You still need authentication and authorization on every protected endpoint.
Where You See This
- Banking applications only show accounts that belong to the signed-in user.
- GitHub uses scopes to control repository access.
- Admin dashboards use roles to restrict management features.
- E-commerce systems verify ownership before displaying orders.
- Security reviews test APIs with multiple users to identify BOLA vulnerabilities.
Common mistakes
| Symptom | Cause | Fix |
|---|---|---|
| Browser console: blocked by CORS policy | The API sends no Access-Control-Allow-Origin for the origin of that page | Add the origin of the page to the allowed list |
| Users can read the orders of others by changing the id | There is no ownership check (BOLA) | Compare the owner of the record with the caller from the token |
| Customers can refund or delete menu items | Only authentication is checked | Add a role check, and return 403 |
| Orders are saved under the wrong customer | The owner is taken from the request body | Take the owner from the token |
A 403 on a guess reveals which ids exist | 403 is used for the records of other people | Return 404 instead |
| A partner token can do everything | There are no scopes, or the scopes are never checked | Check the needed scope on each endpoint |
Exercises
What to Remember
- Authentication asks who are you? (
401). Authorization asks are you allowed? (403or404). - Check ownership on every record. BOLA is the number one API risk.
- Use
404for records that the caller should not know about. Use403for actions that they may not do. - The owner, the user id and the role always come from the token, never from the body.
- Give tokens only the scopes that they need, and deny by default.
Next: API Performance and Caching. You will make your API faster with caching headers, ETags and 304 Not Modified.