Broken Access Control in Strapi with Bearer Tokens
Broken Access Control in Strapi with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Broken Access Control occurs when API endpoints do not properly enforce permission checks, allowing one user to access or modify resources belonging to another. In Strapi, this commonly arises when controllers or policies rely on presence-based authentication (e.g., a Bearer Token) but skip ownership or role-based authorization checks. Because Strapi can be configured to issue JWT Bearer Tokens for authentication, APIs that validate the token but omit granular authorization logic expose unsafe routes to horizontal or vertical privilege escalation.
Consider a Strapi endpoint GET /api/users/:id that returns user profile data. If the route is protected only by an authentication middleware that verifies a Bearer Token but does not ensure that the requesting user’s ID matches the :id parameter, any authenticated user can enumerate or access other users’ data. This is a classic Broken Access Control flaw (OWASP API Top 10 2023:2021-B1). Attackers can use simple iteration over numeric IDs or guess UUIDs if the resource identifiers are predictable.
In a black-box scan, middleBrick tests such scenarios by submitting valid Bearer Tokens from one user context and attempting to access another user’s resources. It checks whether responses inadvertently expose sensitive fields (PII) or allow unauthorized actions. Strapi’s default behavior when using the strapi-plugin-users-permissions is to protect endpoints at the controller level, but developers must explicitly enforce ownership. For example, a policy or controller that does not filter by ctx.state.user.id leads to insecure direct object references (BOLA/IDOR), which middleBrick flags under its BOLA/IDOR and Property Authorization checks.
Another vector involves role-based access without proper scoping. Suppose an endpoint like PUT /api/articles/:articleId is intended only for authors of a given article. If the Bearer Token is accepted but the handler does not verify that the authenticated user is the article’s author, a user with a low-privilege token can modify high-value resources. This maps to BFLA/Privilege Escalation in middleBrick’s checks. Even with JWT Bearer Tokens, missing checks at the business logic layer render authentication insufficient for authorization.
Because Strapi can serve both admin and public APIs, confusion about which endpoints require strict authorization is common. Public routes mistakenly accepting Bearer Tokens, or admin routes missing role checks, create a landscape where Broken Access Control persists. middleBrick validates these conditions by comparing runtime behavior against the OpenAPI spec, looking for missing security schemes, overly permissive scopes, and endpoints that accept tokens but lack ownership or role constraints.
Bearer Tokens-Specific Remediation in Strapi — concrete code fixes
Remediation focuses on ensuring that every authenticated request is validated not only for token validity but also for correct ownership or role. Below are concrete, syntactically correct examples for Strapi v4 using Bearer Tokens via JWT.
1. Enforce ownership in a controller
Instead of fetching a user by ID from the request parameters, derive it from the authenticated context. This ensures users can only access their own data.
// src/api/user/controllers/user.js
'use strict';
module.exports = {
async me(ctx) {
// ctx.state.user is set by the JWT middleware for authenticated requests
const user = await strapi.entityService.findOne('api::user.user', ctx.state.user.id, {
populate: { avatar: true },
});
ctx.body = { data: user };
},
};
2. Add an authorization policy for article updates
Create a policy that checks whether the authenticated user is the author of the article before allowing mutations.
// src/policies/check-author.js
'use strict';
module.exports = async (ctx, next) => {
const articleId = ctx.params.articleId;
const userId = ctx.state.user.id;
const article = await strapi.db.query('api::article.article').findOne({
where: { id: articleId, author: { id: userId } },
});
if (!article) {
ctx.status = 403;
ctx.body = { error: 'Forbidden', message: 'You cannot modify this article' };
return;
}
await next();
};
Register this policy in config/policies.js and apply it to the relevant routes via the route’s policy array.
3. Validate scopes and roles in route configuration
In src/api/article/routes/article.js, explicitly bind policies and ensure the security scheme references Bearer Tokens correctly.
// src/api/article/routes/article.js
module.exports = {
config: {
routes: [
{
method: 'PUT',
path: '/articles/:articleId',
handler: 'article.update',
config: {
policies: ['check-author'], // our custom authorization policy
auth: {
strategies: ['jwt'], // expects Bearer Tokens issued by Strapi
scope: ['update-own-articles'],
},
},
},
],
},
};
4. Securely use Bearer Tokens in requests
When calling Strapi APIs from clients, include the token in the Authorization header. Below is a correct example using fetch.
// Example client request
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'; // a valid JWT from Strapi
fetch('http://localhost:1337/api/articles/42', {
method: 'GET',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
})
.then((res) => res.json())
.then((data) => console.log(data))
.catch((err) => console.error('Unauthorized or forbidden', err));
5. Validate token ownership in a custom middleware
For advanced scenarios, add middleware that enforces resource ownership before reaching controllers.
// src/middlewares/ownership-check/index.js
'use strict';
module.exports = (config, { strapi }) => {
return async (ctx, next) => {
const user = ctx.state.user;
if (!user) {
ctx.status = 401;
return;
}
// Example: ensure user_id in query matches token subject
const resourceUserId = ctx.request.query.userId;
if (resourceUserId && String(resourceUserId) !== String(user.id)) {
ctx.status = 403;
ctx.body = { error: 'Forbidden' };
return;
}
await next();
};
};
These patterns ensure that Bearer Tokens are not treated as a universal access key. By combining token validation with explicit ownership checks and role-based policies, Strapi APIs can effectively mitigate Broken Access Control risks. middleBrick’s scans verify that such controls are present at runtime and map findings to relevant compliance frameworks.