🔐
Protect your public routes in Strapi with a token
Updated At
Jun 25, 2021 07:55 AM
Created
Jun 25, 2021 07:39 AM
Sometimes you need to expose public routes in your Strapi application (perhaps for a build task) but you don't want to make them truly public.
The Strapi docs page do have an article on this but this is for personal access tokens, not an app key. No one else seemed to have written about this - or my Google-fu was poor - so here's an article on it.

Option 1 - Global API Key

If you're not worried about being able to revoke keys used by specific services then this is a good route. We're going to add a new environment variable called API_KEY and create a policy that checks the incoming request has the x-api-key header and that its value matches our API_KEY environment variable.

.env.example

Add a new environment variable in your .env.example
API_KEY=something

config/server.js

Now add the new environment variable as a configuration
module.exports = ({ env }) => ({		
	host: env("HOST", "0.0.0.0"),
  port: env.int("PORT", 1337),
  token: env("TOKEN", "something"), // <- here's the important bit
	// rest of config...
})

The Policy

Create a new file config/policies/token.js. There's nothing fancy going on in here, so no need to break it down line by line. Here's the code:
module.exports = async (ctx, next) => {
    const sentToken = ctx.request.get("x-api-key")
    if (!sentToken) {
        return ctx.unauthorized("No token sent")
    }
    if (sentToken !== strapi.config.get("server.token")) {
        return ctx.unauthorized("Token is invalid")
    }
    return await next()
}

Applying to routes

Now, for your model, you can add this policy to the route. You can do this by opening api/<your-model>/config/routes.json and adding it to the config.policies key on the desired routes. For example
{
	"routes": [
	  {
      "method": "GET",
      "path": "/models",
      "handler": "models.find",
      "config": {
        "policies": ["global::token"] // Again, the important line
      }
	  },
	]
}

Option 2 - Tokens Collection

I won't write a how-to here as I haven't implemented it yet, but I'm sure it's possible! Here's a rough outline of the steps:
  1. Create a tokens collection in your Strapi application. You'll want a "name" and "token" short-text field at the very least on this.
  1. Update the policy we made above to query the collection data and see if the token exists. If it doesn't, we reject, if it does, let the request through

Why can't it be a query parameter, such as ?token=

Good question - Strapi treats this as a filter parameter on the API route. Naturally we don't want to filter our models by the token query parameter so we can't take this route. x-api-key header is the next best thing.