January 6th, 2020 - 4 min read
Two days ago, I read a question on Stackoverflow about a blog app created with React that is using Contentful as the data source.
The problem of the question was something related to React but in the comments, there was a question to the tokens and I'd like to explain each key and how to use them.
The last question in the Contentful FAQ doesn't help for client-side apps as you can not use environment variables to hide your keys.
Keep in mind, anything that is readable by a client-side script can be viewed in the browser console - so never put a personal access key into your code that is running on the client (e.g. a React App) because any malicious user can modify your data.
If you're OK that anybody can read/use your content then it's OK to use the delivery token and space id on client side (see example below).
If you need more protection I think you need a server side or a serverless function (an AWS lambda) so you're not exposing any Contentful keys. With a serverless function you can work with environment variables (e.g. by using dotenv) and store the tokens securely on your hosting server in env. variables.
With Netlify you can use Netlify functions to query (or modify your data) with-out any token on the client.
For Gatsby you're using the space id and access token with environment variables. For example, you can have a look at the source code of this blog.
The tokens are not visible in the created page as the query happens during build time and just the content will be served to the client.
For .env
files just ensure that they're not committed to Github by adding it to .gitignore file. For local development, you create that file from .env.example
(or .contentful.json.sample
). For deployment, you need to add every required env. variable to your hosting server (e.g. for Netlify have a look in the env. docs).
You can find an example React app that's using the delivery token in the following Codesandbox.
I'm just explaining the Contentful related parts here. The file src/api.js
contains everything related to query Contentful.
import { createClient } from "contentful";
const config = {
spaceId: process.env.CONTENTFUL_SPACE_ID,
deliveryToken: process.env.CONTENTFUL_DELIVERY_TOKEN
};
const client = createClient({
space: config.spaceId,
accessToken: config.deliveryToken
});
export const getCourses = () =>
client.getEntries({
content_type: "course",
order: "-sys.createdAt" // Ordering the entries by creation date
});
We're first creating a client instance with createClient
. The config is using the delivery token and space id. It's loaded from the .env
file (required('dotenv').config()
is called in index.js) but you could also hardcode the keys into the config
constant.
The getCourses
method is calling getEntries
method from Contentful.js
- It is returning a Promise that we can wait for with async/await or then
.
content_type: "course"
configures the get request so we only get entries of type course
.order: "-sys.createdAt"
filters for the creation date. The -
reverses the order (newest entry first). For more details about the ordering, you can have a look in the docs.I think for a blog it is OK to use the delivery token client-side as I think it's very unlikely that it will be used somewhere else.
You could also revoke the key and use a new one or do a more complex setup by using a lambda to query your data. But I think the Lambda would make more sense if you also want to modify your data from your client-side app.
Anyway, I'll create an example with a Netlify function in a separate post to show how to query the data.
If anything is not right or I've missed a detail, please leave a comment below.