Skip to main content

Policies

Policies are functions that execute specific logic on each request before it reaches the controller. They are mostly used for securing business logic.

Each route of a Strapi project can be associated to an array of policies. For example, a policy named is-admin could check that the request is sent by an admin user, and restrict access to critical routes.

Policies can be global or scoped. Global policies can be associated to any route in the project. Scoped policies only apply to a specific API or plugin.

Implementation​

A new policy can be implemented:

  • with the interactive CLI command strapi generate
  • or manually by creating a JavaScript file in the appropriate folder (see project structure):
    • ./src/policies/ for global policies
    • ./src/api/[api-name]/policies/ for API policies
    • ./src/plugins/[plugin-name]/policies/ for plugin policies

Global policy implementation example:

./src/policies/is-authenticated.js

module.exports = (policyContext, config, { strapi }) {
if (policyContext.state.user) { // if a session is open
// go to next policy or reach the controller's action
return true;
}

return false; // If you return nothing, Strapi considers you didn't want to block the request and will let it pass
};
./src/policies/is-authenticated.ts

export default (policyContext, config, { strapi }) {
if (policyContext.state.user) { // if a session is open
// go to next policy or reach the controller's action
return true;
}

return false; // If you return nothing, Strapi considers you didn't want to block the request and will let it pass
};

policyContext is a wrapper around the controller context. It adds some logic that can be useful to implement a policy for both REST and GraphQL.

To see a possible advanced usage for route policies, read the policies page of the backend customization examples cookbook. :::

Policies can be configured using a config object:

.src/api/[api-name]/policies/my-policy.js

module.exports = (policyContext, config, { strapi }) {
if (policyContext.state.user.role.code === config.role) { // if user's role is the same as the one described in configuration
return true;
}

return false; // If you return nothing, Strapi considers you didn't want to block the request and will let it pass
};
./src/api/[api-name]/policies/my-policy.ts

export default (policyContext, config, { strapi }) {
if (policyContext.state.user.role.code === config.role) { // if user's role is the same as the one described in configuration
return true;
}

return false; // If you return nothing, Strapi considers you didn't want to block the request and will let it pass
};

Usage​

To apply policies to a route, add them to its configuration object (see routes documentation).

Policies are called different ways depending on their scope:

To list all the available policies, run yarn strapi policies:list. :::

Global policies​

Global policies can be associated to any route in a project.

./src/api/restaurant/routes/custom-restaurant.js

module.exports = {
routes: [
{
method: 'GET',
path: '/restaurants',
handler: 'Restaurant.find',
config: {
/**
Before executing the find action in the Restaurant.js controller,
we call the global 'is-authenticated' policy,
found at ./src/policies/is-authenticated.js.
*/
policies: ['global::is-authenticated']
}
}
]
}
./src/api/restaurant/routes/custom-restaurant.ts

export default {
routes: [
{
method: 'GET',
path: '/restaurants',
handler: 'Restaurant.find',
config: {
/**
Before executing the find action in the Restaurant.js controller,
we call the global 'is-authenticated' policy,
found at ./src/policies/is-authenticated.js.
*/
policies: ['global::is-authenticated']
}
}
]
}

Plugin policies​

Plugins can add and expose policies to an application. For example, the Users & Permissions plugin comes with policies to ensure that the user is authenticated or has the rights to perform an action:

./src/api/restaurant/routes/custom-restaurant.js

module.exports = {
routes: [
{
method: 'GET',
path: '/restaurants',
handler: 'Restaurant.find',
config: {
/**
The `isAuthenticated` policy prodived with the `users-permissions` plugin
is executed before the `find` action in the `Restaurant.js` controller.
*/
policies: ['plugin::users-permissions.isAuthenticated']
}
}
]
}
./src/api/restaurant/routes/custom-restaurant.ts

export default {
routes: [
{
method: 'GET',
path: '/restaurants',
handler: 'Restaurant.find',
config: {
/**
The `isAuthenticated` policy prodived with the `users-permissions` plugin
is executed before the `find` action in the `Restaurant.js` controller.
*/
policies: ['plugin::users-permissions.isAuthenticated']
}
}
]
}

API policies​

API policies are associated to the routes defined in the API where they have been declared.

./src/api/restaurant/policies/is-admin.js.

module.exports = async (policyContext, config, { strapi }) {
if (policyContext.state.user.role.name === 'Administrator') {
// Go to next policy or will reach the controller's action.
return true;
}

return false;
};
./src/api/restaurant/routes/custom-restaurant.js

module.exports = {
routes: [
{
method: 'GET',
path: '/restaurants',
handler: 'Restaurant.find',
config: {
/**
The `is-admin` policy found at `./src/api/restaurant/policies/is-admin.js`
is executed before the `find` action in the `Restaurant.js` controller.
*/
policies: ['is-admin']
}
}
]
}


./src/api/restaurant/policies/is-admin.ts

export default (policyContext, config, { strapi }) {
if (policyContext.state.user.role.name === 'Administrator') {
// Go to next policy or will reach the controller's action.
return true;
}

return false;
};

./src/api/restaurant/routes/custom-restaurant.ts

export default {
routes: [
{
method: 'GET',
path: '/restaurants',
handler: 'Restaurant.find',
config: {
/**
The `is-admin` policy found at `./src/api/restaurant/policies/is-admin.js`
is executed before the `find` action in the `Restaurant.ts` controller.
*/
policies: ['is-admin']
}
}
]
}

To use a policy in another API, reference it with the following syntax: api::[apiName].[policyName]:

./src/api/category/routes/custom-category.js

module.exports = {
routes: [
{
method: 'GET',
path: '/categories',
handler: 'Category.find',
config: {
/**
The `is-admin` policy found at `./src/api/restaurant/policies/is-admin.js`
is executed before the `find` action in the `Restaurant.js` controller.
*/
policies: ['api::restaurant.is-admin']
}
}
]
}
./src/api/category/routes/custom-category.ts

export default {
routes: [
{
method: 'GET',
path: '/categories',
handler: 'Category.find',
config: {
/**
The `is-admin` policy found at `./src/api/restaurant/policies/is-admin.ts`
is executed before the `find` action in the `Restaurant.js` controller.
*/
policies: ['api::restaurant.is-admin']
}
}
]
}