Skip to content
On this page

Security Best Practices For Headless CMS Projects ​

This guide covers best practices for security, authentication, and permissions within the context of Headless CMS.

A Headless CMS, when coupled with statically-generated sites, are architecture choices that are generally more secure than Traditional CMS because your content is separated from the presentation layer. Given that users don't directly interact with a server to construct a page, there is a reduced ability for malicious actors to attack the website. However, it is still very important that you follow good security protocols to keep your data protected.

In this guide, we'll cover some best practices for keeping your Directus Headless CMS secure.

Restrict Public Role ​

Directus makes it super easy to share your content with our REST and GraphQL APIs.

The Public role within Access Control defines what content is available without authentication. To be safe, all permissions are turned off by default. This means that no data is available via the API without providing a proper access token. Your use case may allow all data to be public, but it may instead require restricted access.

If you do want to make data public, we recommend these guidelines.

  • On your public role, only enable read access.

  • Consider defining a Custom Permission for read operations to control which items are available and which fields within those items consumers can see.

    The custom permissions interface for the Public role is displayed. The Item Permissions table is active and one Rule is active - "Status" Equals "Published".

    Standard read permissions grant access to ALL data within a collection which means the general public could see unpublished content you might not want them to see.

  • Do not enable create, update, or delete access for collections within the Public role. This opens your instance up for attack from spammers and other bad actors.

Create Scoped Roles For Specific Purposes ​

As a general security rule, you should only share the minimum amount of data that is needed to achieve your goal.

For an example website use case, you might have several different types of users and roles that need access to various levels of data.

  • Website API - role and user for reading content from the API (pages, posts, etc) and creating form submissions.
  • Guest Author - restricted role where guest post authors can only update their own content.
  • Content Manager - non-admin role that grants full CRUD access to all collections except business analytics.

For each of these roles, allow access only to the collections and specific CRUD operations that each role needs to perform their function.

Our guide on Content Approval Workflows is helpful for scoping roles and permissions.

Obscure Access Tokens and URLs ​

There are three ways to authenticate with Directus – Temporary Tokens (JWT), Session Tokens (JWT) or Static tokens.

Temporary Tokens and Session Tokens are generated by the login endpoint. They are short-lived and generally more secure.

Static tokens are set for each user and never expire. They are handy to use for server-to-server communication.

If you are using Static Tokens and your website or frontend is built using a static site generator (SSG) or calls your API on the client side, then you could be exposing your access token.

To obscure your Directus Access Tokens and URL:

  1. Never store access tokens inside your code or repository. Use a .env file to store secrets and sensitive credentials like access tokens.

  2. Call your API from the server-side. Frontend frameworks like Next.js and Nuxt.js have "server" routes that you can setup that are only called from the server, never on the client.

    You can also use serverless functions or backend proxies to hide them from public view. Some website deployment platforms include serverless functions as part of their offering.

Be Careful When Granting Admin Access ​

In a typical Directus project, there’s only a small group of people that truly need the Administrator role. The Administrator role provides full-access to CRUD+S Operations on every collection and rights to change any project settings, roles, data models, etc.

When granting Admin access, make sure that it is only provided to those individuals who require it to perform their job responsibilities. Too many Admins or granting Admin access to those who don’t truly need it can put the security of your Directus instance at risk.

Require Two-Factor Authentication and Secure Passwords ​

Many data breaches can be attributed back to sharing passwords or using the same password across many different sites.

While in the development phase of your project, it can certainly be easier and quicker to use weak passwords for testing purposes.

But when it’s time to go to production and add all your different users, we recommend the following:

  1. Enable and enforce two-factor authentication.

    Two-factor authentication can be enforced for each specific role by checking the Require 2FA field in a role's settings.

    The Administrator role settings page is displayed. The Require 2FA form field is highlighted and enabled.

    Individual users can enable two-factor authentication by checking the Two-Factor Authentication field on their own user detail page and confirming their password.

    A sample user's detail page is shown. The Two-Factor Authentication form field is highlighted.

  2. Enable the Strong option for Auth Password Policy under Project Settings > Security.

    The Project Settings page is shown. The Security section is highlighted. Within the Security, section there are two fields shown: Auth Password Policy and Auth Login Attempts.

Use Different Project Names Between Environments

The project name is used in two-factor authentication for identification. Remember to set a different project name to differentiate between environments to prevent the authenticator application from overriding the token for a different environment.

For example:

EnvironmentProject Name
StagingDirectus Staging
DevelopmentDirectus Dev