At this point in the tutorial, if you were to expose your website and code to the internet, you would likely become susceptible to critical breaches. That's because there are two additional steps to undergo before publishing your work. So don't underestimate these tips and put on your serious face; it's time to get ready for production.


Tutorial outline:

  1. Bootstrap the project
  2. Implement the preview page
  3. Get ready for production (you are here ๐Ÿ“)

Refactor API Credentials

Storing credentials in your source code is an accident waiting to happen. More and more these days, we version our code and push our projects onto publicly accessible repositories. This practice is excellent to share and seek new knowledge, but it also poses a security risk.

In the present case, by scouting your code, other applications may connect to your Ghost instance with full admin rights. As long as your server resides on your local network, this is not a big deal, but as soon as it becomes remotely accessible, it turns into a huge risk.

To avoid this kind of issue, it's common practice to store application secrets into separate, non-tracked files. Sure, anytime anyone clones the repository, they will have to populate those files by hand, but that's a small price to pay for a much greater good.

In GatsbyJS, you can define client-side secrets (environment variables) by creating a new .env.development configuration file. You can populate this file with key-value pairs; however, only those keys starting with GATSBY_ will become available to the browser. Make sure to prefix your variables accordingly.

GATSBY_GHOST_ADMIN_URL=http://localhost:3001
GATSBY_GHOST_ADMIN_KEY=<YOUR GHOST ADMIN KEY>
.env

A quick tip: it's good practice to duplicate this file, rename it to .env.development.sample, and replace your sensitive data with dummy values.

Older versions of the gatsby-starter-ghost starter didn't use to ignore this file. If yours doesn't either, add this line to your .gitignore.

# line 61
.env.development
.gitignore

Then, in your preview component, replace the previously hard-coded variables with the following snippet.

// line 9
const api = new GhostAdminAPI({
    url: process.env.GATSBY_GHOST_ADMIN_URL,
    key: process.env.GATSBY_GHOST_ADMIN_KEY,
    version: `v3`,
})
preview.js

If you had already committed your code before performing these steps, you should also generate a new admin key for your integration. From your Ghost back-end, navigate to Settings > Integrations > Custom Integrations > Gatsby, move your mouse over the admin API key, and click on the Regenerate button that should appear on the right.

Regenerate the admin API key

Hide Previews on Production

Since you made your admin keys available to the browser, those same keys are accessible to any visitor. Even without digging through the minified code, any authenticated call to the API can be intercepted, tampered with, and sent back to perform potentially disruptive tasks. That's why you should disable your preview page entirely when going live.

Browsers let users edit and resend requests at their will

To do so, you can adjust the plugin configuration based on the current environment. Depending on what command you used to compile your website (gatsby develop or gatsby build), the process.env.NODE_ENV variable will hold the context of your application: development or production.

Hence, based on this variable, you can include the gatsby-plugin-create-client-paths plugin when Gatsby is in development mode, and filter out the preview page from your default gatsby-plugin-page-creator configuration when it's not.

You should also remove the redundant gatsby-source-filesystem declaration on line 48. As explained in a previous article, an implicit gatsby-plugin-page-creator configuration already takes care of the components in your src/pages directory, so it's safe to remove.

// line 29
/**
 * Development-only plugins
 */
const devPlugins = [
    {
        resolve: `gatsby-plugin-create-client-paths`,
        options: { prefixes: [`/preview/*`] },
    },
]

/**
 * Production-only plugins
 */
const prodPlugins = [
    {
        // This plugin is usually active by default, but by making it specific
        // you can override its options. In this case, the ignore key.
        resolve: `gatsby-plugin-page-creator`,
        options: {
            path: path.join(__dirname, `src`, `pages`),
            ignore: [`preview.js`],
        },
    },
]

/**
* This is the place where you can tell Gatsby which plugins to use
* and set them up the way you want.
*
* Further info ๐Ÿ‘‰๐Ÿผ https://www.gatsbyjs.org/docs/gatsby-config/
*
*/
module.exports = {
    siteMetadata: {
        siteUrl: config.siteUrl,
    },
    plugins: [
        /**
         * Environment-dependent plugins
         */
        ...(process.env.NODE_ENV === `development` ? devPlugins : prodPlugins),
        /**
         *  Content Plugins
         */
        // ...
gatsby-config.js

Conclusion

I hope this tutorial helped you deliver what it promised: a preview page capable of displaying Ghost's drafts in GatsbyJS. As always, the code is freely available on GitHub, and I'm ready to answer any follow-up question on Twitter. Cheers!