├── .gitignore ├── README.md ├── gatsby-browser.js ├── gatsby-config.js ├── gatsby-ssr.js ├── lib └── apolloClient.ts ├── package-lock.json ├── package.json └── src ├── components ├── AuthContent.tsx ├── CreatePostForm.tsx ├── Header.tsx ├── Layout.tsx ├── LogInForm.tsx ├── Nav.tsx ├── ProfileForm.tsx ├── SendPasswordResetEmailForm.tsx ├── SetPasswordForm.tsx ├── SignUpForm.tsx └── UnAuthContent.tsx ├── hooks └── useAuth.tsx ├── images └── icon.png ├── pages ├── 404.tsx ├── create-post.tsx ├── forgot-password.tsx ├── index.tsx ├── log-in.tsx ├── log-out.tsx ├── members.tsx ├── profile.tsx ├── set-password.tsx └── sign-up.tsx └── styles └── global.css /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .cache/ 3 | public 4 | .env* 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Headless WordPress Authentication with Native Cookies - Gatsby 2 | 3 | This Gatsby app is a port of the Next.js app codebase from this blog post: https://developers.wpengine.com/blog/headless-wordpress-authentication-native-cookies/ 4 | 5 | This app shows how to authenticate users using WordPress' own native auth cookies. 6 | 7 | ## Steps to Use: 8 | 9 | 1. Clone down this repo 10 | 1. Create a `.env.development` file inside of the app’s root folder. Open that file in a text editor and paste in `GATSBY_WORDPRESS_API_URL=https://headlesswpcookieauth.local/graphql`, replacing `headlesswpcookieauth.local` with the domain for your local WordPress site. This is the endpoint that Apollo Client will use when it sends requests to your WordPress backend. 11 | 1. Run `npm install` (or `yarn`) to install the app’s NPM dependencies. 12 | 1. Run `npm run develop` to get the server running locally. 13 | 1. You should now be able to visit http://localhost:8000/ in a web browser and see the app’s homepage. 14 | 15 | See the blog post linked above for details on how to set up the WordPress backend, and for a tour of the app's features. 16 | -------------------------------------------------------------------------------- /gatsby-browser.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { ApolloProvider } from "@apollo/client"; 3 | 4 | import { client } from "./lib/apolloClient"; 5 | import { AuthProvider } from "./src/hooks/useAuth"; 6 | import "./src/styles/global.css"; 7 | 8 | export const wrapRootElement = ({ element }) => ( 9 | 10 | {element} 11 | 12 | ); 13 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config({ 2 | path: `.env.${process.env.NODE_ENV}`, 3 | }); 4 | 5 | module.exports = { 6 | siteMetadata: { 7 | title: "headless-wp-cookie-auth-gatsby", 8 | }, 9 | plugins: [ 10 | { 11 | resolve: "gatsby-source-wordpress", 12 | options: { 13 | url: process.env.GATSBY_WORDPRESS_API_URL, 14 | }, 15 | }, 16 | ], 17 | }; 18 | -------------------------------------------------------------------------------- /gatsby-ssr.js: -------------------------------------------------------------------------------- 1 | import "./src/styles/global.css"; 2 | 3 | export { wrapRootElement } from "./gatsby-browser"; 4 | -------------------------------------------------------------------------------- /lib/apolloClient.ts: -------------------------------------------------------------------------------- 1 | import fetch from "cross-fetch"; 2 | import { ApolloClient, InMemoryCache, createHttpLink } from "@apollo/client"; 3 | 4 | const link = createHttpLink({ 5 | uri: process.env.GATSBY_WORDPRESS_API_URL, 6 | credentials: 'include', 7 | fetch, 8 | }); 9 | 10 | export const client = new ApolloClient({ 11 | cache: new InMemoryCache(), 12 | link, 13 | }); 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "headless-wp-cookie-auth-gatsby", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "headless-wp-cookie-auth-gatsby", 6 | "author": "Kellen Mace", 7 | "keywords": [ 8 | "gatsby" 9 | ], 10 | "scripts": { 11 | "develop": "gatsby develop", 12 | "start": "gatsby develop", 13 | "build": "gatsby build", 14 | "serve": "gatsby serve", 15 | "clean": "gatsby clean" 16 | }, 17 | "dependencies": { 18 | "@apollo/client": "^3.3.20", 19 | "cross-fetch": "^3.1.4", 20 | "dotenv": "^8.6.0", 21 | "gatsby": "^3.6.2", 22 | "gatsby-plugin-sharp": "^3.8.0", 23 | "gatsby-source-wordpress": "^5.8.0", 24 | "gatsby-transformer-sharp": "^3.8.0", 25 | "react": "^17.0.1", 26 | "react-dom": "^17.0.1" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/components/AuthContent.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { useEffect, ReactNode } from "react"; 3 | import { navigate } from "gatsby"; 4 | 5 | import useAuth from "../hooks/useAuth"; 6 | 7 | export default function AuthContent({ children }: { children: ReactNode }) { 8 | const { loggedIn, loading } = useAuth(); 9 | 10 | // Navigate unauthenticated users to Log In page. 11 | useEffect(() => { 12 | if (!loading && !loggedIn) { 13 | navigate('/log-in'); 14 | } 15 | }, [loggedIn, loading, navigate]); 16 | 17 | if (loggedIn) { 18 | return <>{children}; 19 | } 20 | 21 | return

Loading...

; 22 | } 23 | -------------------------------------------------------------------------------- /src/components/CreatePostForm.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { useMutation, gql } from "@apollo/client"; 3 | 4 | const CREATE_POST = gql` 5 | mutation createPost($title: String!, $content: String!) { 6 | createPost(input: { 7 | title: $title 8 | content: $content 9 | status: PUBLISH 10 | }) { 11 | post { 12 | databaseId 13 | } 14 | } 15 | } 16 | `; 17 | 18 | export default function CreatePostForm() { 19 | const [createPost, { data, loading, error }] = useMutation(CREATE_POST); 20 | const wasPostCreated = Boolean(data?.createPost?.post?.databaseId); 21 | 22 | function handleSubmit(event: React.FormEvent) { 23 | event.preventDefault(); 24 | const data = new FormData(event.currentTarget); 25 | const values = Object.fromEntries(data); 26 | createPost({ 27 | variables: values 28 | }).catch(error => { 29 | console.error(error); 30 | }); 31 | } 32 | 33 | if (wasPostCreated) { 34 | return ( 35 |

Post successfully created.

36 | ); 37 | } 38 | 39 | return ( 40 |
41 |
42 | 43 | 49 | 50 |