{
  "doc": {
    "id": "app/write-tests/authentication/google-authentication",
    "title": "Testing Google authentication in Cypress",
    "description": "Test Google (OAuth) login in Cypress using cy.origin(), and cache authenticated sessions with cy.session().",
    "section": "app",
    "source_path": "/llm/markdown/app/write-tests/authentication/google-authentication.md",
    "version": "066c46e056f0f322a0670d2d3aa4e6adaebfe717",
    "updated_at": "2026-09-10T13:30:12.426Z",
    "headings": [
      {
        "id": "app/write-tests/authentication/google-authentication#google-authentication",
        "text": "Google Authentication",
        "level": 1
      },
      {
        "id": "app/write-tests/authentication/google-authentication#google-project-and-application-setup",
        "text": "Google Project and Application Setup",
        "level": 2
      },
      {
        "id": "app/write-tests/authentication/google-authentication#using-the-google-oauth-2-0-playground-to-create-testing-credentials",
        "text": "Using the Google OAuth 2.0 Playground to Create Testing Credentials",
        "level": 2
      },
      {
        "id": "app/write-tests/authentication/google-authentication#setting-google-app-credentials-in-cypress",
        "text": "Setting Google app credentials in Cypress",
        "level": 2
      },
      {
        "id": "app/write-tests/authentication/google-authentication#custom-command-for-google-authentication",
        "text": "Custom Command for Google Authentication",
        "level": 2
      },
      {
        "id": "app/write-tests/authentication/google-authentication#adapting-a-google-app-for-testing",
        "text": "Adapting a Google App for Testing",
        "level": 2
      },
      {
        "id": "app/write-tests/authentication/google-authentication#adapting-the-back-end",
        "text": "Adapting the back end",
        "level": 3
      },
      {
        "id": "app/write-tests/authentication/google-authentication#adapting-the-front-end",
        "text": "Adapting the front end",
        "level": 3
      }
    ]
  },
  "content": {
    "type": "root",
    "children": [
      {
        "type": "heading",
        "depth": 1,
        "children": [
          {
            "type": "text",
            "value": "Google Authentication"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The technique we'll use for testing is to use the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://developers.google.com/oauthplayground",
            "children": [
              {
                "type": "text",
                "value": "Google OAuth 2.0 Playground"
              }
            ]
          },
          {
            "type": "text",
            "value": " to create a refresh token that can be exchanged for an access token and id token during the testing phase."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Google Project and Application Setup"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "First, a "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://google.com",
            "children": [
              {
                "type": "text",
                "value": "Google"
              }
            ]
          },
          {
            "type": "text",
            "value": " project is required. If you don't already have a project, you can create one using the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://console.cloud.google.com",
            "children": [
              {
                "type": "text",
                "value": "Google Cloud Console"
              }
            ]
          },
          {
            "type": "text",
            "value": ". More information is available in the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://cloud.google.com/apis/docs/getting-started#creating_a_google_project",
            "children": [
              {
                "type": "text",
                "value": "Google Cloud APIs Getting Started"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Next, use the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://console.developers.google.com/APIs",
            "children": [
              {
                "type": "text",
                "value": "Google API Console"
              }
            ]
          },
          {
            "type": "text",
            "value": " to "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://console.developers.google.com/apis/credentials",
            "children": [
              {
                "type": "text",
                "value": "create credentials"
              }
            ]
          },
          {
            "type": "text",
            "value": " for your web application. In the top navigation, click `Create Credentials` and choose `OAuth client ID`."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "On the `Create OAuth client ID` page, enter the following:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Application Type: Web Application"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Name: Your Web Application Name"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Authorized JavaScript origins: `http://localhost:3000`"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Authorized redirect URIs: `http://localhost:3000/callback` and `https://developers.google.com/oauthplayground`"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Once saved, note the client ID and client secret. You can find these under the \"OAuth 2.0 Client IDs\" on the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://console.developers.google.com/apis/credentials",
            "children": [
              {
                "type": "text",
                "value": "Google API Credentials"
              }
            ]
          },
          {
            "type": "text",
            "value": " page."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "You must also configure an OAuth Consent Screen and add your test account(s) as test users before the credentials will work. Refer to "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://developers.google.com/identity/protocols/oauth2",
            "children": [
              {
                "type": "text",
                "value": "Google's OAuth setup documentation"
              }
            ]
          },
          {
            "type": "text",
            "value": " for instructions."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Using the Google OAuth 2.0 Playground to Create Testing Credentials"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The refresh token from this process is unique to the authenticated Google user. This process must be repeated for each user intended for testing."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Visit the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://developers.google.com/oauthplayground",
            "children": [
              {
                "type": "text",
                "value": "Google OAuth 2.0 Playground"
              }
            ]
          },
          {
            "type": "text",
            "value": ". Click the icon in the upper right corner to reveal a `OAuth 2.0 configuration` panel. In this panel set the following:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "OAuth flow: Server-side"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Access type: Offline"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Check `Use your own OAuth credentials`."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "OAuth Client ID: Your Google Application Client ID"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "OAuth Client secret: Your Google Application Client Secret"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Select the Google APIs needed for your application under Step 1 (Select & authorize APIs), including the `https://www.googleapis.com/auth/userinfo.profile` endpoint under Google OAuth2 API v2 at a minimum. Click Authorize APIs."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Next, sign in with Google credentials to your test Google user account. You'll be redirected back to the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://developers.google.com/oauthplayground",
            "children": [
              {
                "type": "text",
                "value": "Google OAuth 2.0 Playground"
              }
            ]
          },
          {
            "type": "text",
            "value": " under Step 2 (Exchange authorization code for tokens). Click the Exchange authorization code for token button."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "You'll be taken to Step 3 (Configure request to API). Note the returned refresh token to be used with testing."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Setting Google app credentials in Cypress"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "To have access to test user credentials within our tests we need to configure Cypress to use the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://google.com",
            "children": [
              {
                "type": "text",
                "value": "Google"
              }
            ]
          },
          {
            "type": "text",
            "value": " environment variables set in the `.env` file."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": ".env"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "REACT_APP_GOOGLE_CLIENTID = 'your-client-id'\nREACT_APP_GOOGLE_CLIENT_SECRET = 'your-client-secret'\nGOOGLE_REFRESH_TOKEN = 'your-refresh-token'"
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "cypress.config.js"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "cypress.config.ts"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "const { defineConfig } = require('cypress')\n// Populate process.env with values from .env file\nrequire('dotenv').config()\n\nmodule.exports = defineConfig({\n  env: {\n    googleClientId: process.env.VITE_GOOGLE_CLIENTID,\n    googleClientSecret: process.env.VITE_GOOGLE_CLIENT_SECRET,\n    googleRefreshToken: process.env.GOOGLE_REFRESH_TOKEN,\n  },\n})"
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "import { defineConfig } from 'cypress'\n// Populate process.env with values from .env file\nrequire('dotenv').config()\n\nexport default defineConfig({\n  env: {\n    googleClientId: process.env.VITE_GOOGLE_CLIENTID,\n    googleClientSecret: process.env.VITE_GOOGLE_CLIENT_SECRET,\n    googleRefreshToken: process.env.GOOGLE_REFRESH_TOKEN,\n  },\n})"
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Custom Command for Google Authentication"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Next, we'll write a command named `loginByGoogleApi` to perform a programmatic login into Google and set an item in `localStorage` with the authenticated users details, which we'll use in our application code to verify we are authenticated under test."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The `loginByGoogleApi` command will execute the following steps:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": true,
        "start": 1,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Use the refresh token from the "
                  },
                  {
                    "type": "link",
                    "title": null,
                    "url": "https://developers.google.com/oauthplayground",
                    "children": [
                      {
                        "type": "text",
                        "value": "Google OAuth 2.0 Playground"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": " to perform the programmatic login, exchanging the refresh token for an `access_token`."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Use the `access_token` returned to get the Google User profile."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Finally the `googleCypress` localStorage item is set with the `access token` and user profile."
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "cypress/support/commands.js"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "cypress/support/commands.ts"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "cypress/support/commands.js"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "Cypress.Commands.add('loginByGoogleApi', () => {\n  cy.log('Logging in to Google')\n  cy.env(['googleClientId', 'googleClientSecret', 'googleRefreshToken']).then(({ clientId, clientSecret, refreshToken }) => {\n    cy.request({\n      method: 'POST',\n      url: 'https://oauth2.googleapis.com/token',\n      body: {\n        grant_type: 'refresh_token',\n        client_id: clientId,\n        client_secret: clientSecret,\n        refresh_token: refreshToken,\n      },\n    }).then(({ body }) => {\n    const { access_token, id_token } = body\n\n    cy.request({\n      method: 'GET',\n      url: 'https://www.googleapis.com/oauth2/v3/userinfo',\n      headers: { Authorization: `Bearer ${access_token}` },\n    }).then(({ body }) => {\n      cy.log(body)\n      const userItem = {\n        token: id_token,\n        user: {\n          googleId: body.sub,\n          email: body.email,\n          givenName: body.given_name,\n          familyName: body.family_name,\n          imageUrl: body.picture,\n        },\n      }\n\n      window.localStorage.setItem('googleCypress', JSON.stringify(userItem))\n      cy.visit('/')\n    })\n  })\n})"
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "declare global {\n  namespace Cypress {\n    interface Chainable {\n      loginByGoogleApi(): Chainable<void>\n    }\n  }\n}\n\nCypress.Commands.add('loginByGoogleApi', () => {\n  cy.log('Logging in to Google')\n  cy.env(['googleClientId', 'googleClientSecret', 'googleRefreshToken']).then(\n    ({ clientId, clientSecret, refreshToken }) => {\n      cy.request({\n        method: 'POST',\n        url: 'https://oauth2.googleapis.com/token',\n        body: {\n          grant_type: 'refresh_token',\n          client_id: clientId,\n          client_secret: clientSecret,\n          refresh_token: refreshToken,\n        },\n      }).then(({ body }) => {\n        const { access_token, id_token } = body\n\n        cy.request({\n          method: 'GET',\n          url: 'https://www.googleapis.com/oauth2/v3/userinfo',\n          headers: { Authorization: `Bearer ${access_token}` },\n        }).then(({ body }) => {\n          cy.log(body)\n          const userItem = {\n            token: id_token,\n            user: {\n              googleId: body.sub,\n              email: body.email,\n              givenName: body.given_name,\n              familyName: body.family_name,\n              imageUrl: body.picture,\n            },\n          }\n\n          window.localStorage.setItem('googleCypress', JSON.stringify(userItem))\n          cy.visit('/')\n        })\n      })\n    }\n  )\n})"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "With our Google app setup properly, necessary environment variables in place, and our `loginByGoogleApi` command implemented, we'll be able to authenticate with Google while our app is under test. Below is a test to login as a user via Google, complete the onboarding process and logout."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Try it out"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-realworld-app/blob/develop/cypress/tests/ui-auth-providers/google.spec.ts",
            "children": [
              {
                "type": "text",
                "value": "runnable version of this test"
              }
            ]
          },
          {
            "type": "text",
            "value": " is in the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-realworld-app",
            "children": [
              {
                "type": "text",
                "value": "Real World App (RWA)"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "auth.cy.js"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "describe('Google', function () {\n  beforeEach(function () {\n    cy.task('db:seed')\n    cy.loginByGoogleApi()\n  })\n\n  it('shows onboarding', function () {\n    cy.contains('Get Started').should('be.visible')\n  })\n})"
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Adapting a Google App for Testing"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Note"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The previous sections focused on the recommended Google authentication practice within Cypress tests. To use this practice it's assumed you're testing an app appropriately built or adapted to use Google."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The following sections provides guidance on building or adapting an app to use Google authentication."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-realworld-app",
            "children": [
              {
                "type": "text",
                "value": "Real World App (RWA)"
              }
            ]
          },
          {
            "type": "text",
            "value": " is used and provides configuration and runnable code for both the React SPA and the Express back end."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The front end uses the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/anthonyjgrove/react-google-login",
            "children": [
              {
                "type": "text",
                "value": "react-google-login component"
              }
            ]
          },
          {
            "type": "text",
            "value": " and the back end uses "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/auth0/express-jwt",
            "children": [
              {
                "type": "text",
                "value": "express-jwt"
              }
            ]
          },
          {
            "type": "text",
            "value": " to validate the JWT provided by Google."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Use the `yarn dev:google` command when starting the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-realworld-app",
            "children": [
              {
                "type": "text",
                "value": "Cypress Real World App"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Adapting the back end"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "In order to validate API requests from the frontend, we install "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/auth0/express-jwt",
            "children": [
              {
                "type": "text",
                "value": "express-jwt"
              }
            ]
          },
          {
            "type": "text",
            "value": " and "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/auth0/node-jwks-rsa",
            "children": [
              {
                "type": "text",
                "value": "jwks-rsa"
              }
            ]
          },
          {
            "type": "text",
            "value": " and configure validation for JWT's from Google."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "backend/helpers.ts"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "import jwt from 'express-jwt'\nimport jwksRsa from 'jwks-rsa'\n\ndotenv.config()\nconst googleJwtConfig = {\n  secret: jwksRsa.expressJwtSecret({\n    cache: true,\n    rateLimit: true,\n    jwksRequestsPerMinute: 5,\n    jwksUri: 'https://www.googleapis.com/oauth2/v3/certs',\n  }),\n  // Validate the audience and the issuer.\n  audience: process.env.REACT_APP_GOOGLE_CLIENTID,\n  issuer: 'accounts.google.com',\n  algorithms: ['RS256'],\n}"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Next, we'll define an Express middleware function to be use in our routes to verify the Google JWT sent by the front end API requests as the `Bearer` token."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "backend/helpers.ts"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "// ...\nexport const checkJwt = jwt(googleJwtConfig).unless({ path: ['/testData/*'] })"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Once this helper is defined, we can use globally to apply to all routes:"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "backend/app.ts"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "// initial imports ...\nimport { checkJwt } from './helpers'\n\n// ...\nif (process.env.REACT_APP_GOOGLE) {\n  app.use(checkJwt)\n}\n// routes ..."
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Adapting the front end"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "We need to update our front end React app to allow for authentication with Google. As mentioned above, the front end uses the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/anthonyjgrove/react-google-login",
            "children": [
              {
                "type": "text",
                "value": "react-google-login component"
              }
            ]
          },
          {
            "type": "text",
            "value": " to perform the login."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "First, we create an `AppGoogle.tsx` container to render our application as it is authenticated with Google. The component is identical to the `App.tsx` component, but has the addition of a `GoogleLogin` component in place of the original Sign Up and Sign In components."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "A `useGoogleLogin` hook is added to send a `GOOGLE` event with the `user` and `token` objects to work with the existing authentication layer (`authMachine.ts`)."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The full "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-realworld-app/blob/develop/src/containers/AppGoogle.tsx",
            "children": [
              {
                "type": "text",
                "value": "AppGoogle.tsx component"
              }
            ]
          },
          {
            "type": "text",
            "value": " is in the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-realworld-app",
            "children": [
              {
                "type": "text",
                "value": "Real World App (RWA)"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "containers/AppGoogle.tsx"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "// initial imports ...\nimport { GoogleLogin, useGoogleLogin } from 'react-google-login'\n// ...\nconst AppGoogle = () => {\n  // ...\n  useGoogleLogin({\n    clientId: process.env.REACT_APP_GOOGLE_CLIENTID!,\n    onSuccess: (res) => {\n      authService.send('GOOGLE', { user: res.profileObj, token: res.tokenId })\n    },\n    cookiePolicy: 'single_host_origin',\n    isSignedIn: true,\n  })\n  // ...\n  const isLoggedIn =\n    isAuthenticated &&\n    (authState.matches('authorized') ||\n      authState.matches('refreshing') ||\n      authState.matches('updating'))\n  return (\n    <div className={classes.root}>\n      // ...\n      {authState.matches('unauthorized') && (\n        <Container component=\"main\" maxWidth=\"xs\">\n          <CssBaseline />\n          <div className={classes.paper}>\n            <GoogleLogin\n              clientId={process.env.REACT_APP_GOOGLE_CLIENTID!}\n              buttonText=\"Login\"\n              cookiePolicy={'single_host_origin'}\n            />\n          </div>\n        </Container>\n      )}\n    </div>\n  )\n}\nexport default AppGoogle"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Next, we update our entry point (`index.tsx`) to conditionally load the `AppGoogle` component if we start the application with the `REACT_APP_GOOGLE` environment variable set to `true`."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "src/index.tsx"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "import React from 'react'\nimport ReactDOM from 'react-dom'\nimport { Router } from 'react-router-dom'\nimport { history } from './utils/historyUtils'\nimport App from './containers/App'\nimport AppGoogle from './containers/AppGoogle'\nimport { createMuiTheme, ThemeProvider } from '@material-ui/core'\nconst theme = createMuiTheme({\n  palette: {\n    secondary: {\n      main: '#fff',\n    },\n  },\n})\nReactDOM.render(\n  <Router history={history}>\n    <ThemeProvider theme={theme}>\n      {process.env.REACT_APP_GOOGLE ? <AppGoogle /> : <App />}\n    </ThemeProvider>\n  </Router>,\n  document.getElementById('root')\n)"
      }
    ]
  },
  "token_estimate": 1884
}