When testing a browser-side application that uses Google Drive, the normal user flow usually looks like this:
Open the app
Click Google Drive authorization
Choose a Google account
Approve Google Drive access
Return to the app
Use Google Drive featuresThis works for real users, but it is not a good flow for automated Playwright tests.
Google sign-in and OAuth consent pages may reject automated browsers, require extra account checks, or show security warnings. For that reason, I do not want Playwright to automate the Google OAuth screen.
Instead, I want the test to start with an already-authorized Google Drive access token.
This article shows how to generate a Google Drive access token before running Playwright, then inject that token into a browser-side app.
Scope of This Article
This article focuses on SPA / browser-side Google Drive integrations.
In this kind of app, the browser receives a Google Drive access token and calls the Google Drive API directly.
This article does not cover the server-side pattern.
For a server-side web application, the backend should usually store the Google refresh token, exchange it for an access token, and call Google Drive from the server side. In that case, Playwright should not receive the Google token directly.
Assumption
This article assumes the application already works with Google Drive manually.
That means the normal Google Drive setup is already done:
Google Drive API is already enabled
OAuth consent screen is already configured
The app already has a Google OAuth client
The app can already ask the user to authorize Google Drive
The app can already call the Google Drive API after authorizationThose are normal Google Drive integration steps. They are not specific to Playwright.
This article only covers the extra setup needed to produce an access token before running Playwright tests.
Goal
The goal is to run Playwright tests against a real Google Drive account without manually clicking through the Google OAuth screen during every test run.
The final flow looks like this:
refresh_token
→ exchange for access_token
→ pass access_token to Playwright
→ inject access_token into the browser
→ browser-side app calls the real Google Drive APIThis is useful when:
The test needs to use the real Google Drive API
The Google OAuth consent screen should not be automated by Playwright
The application already has a working Google Drive authorization flow
The test needs a repeatable way to start from an already-authorized Google Drive stateWhy Not Automate the Google OAuth Page?
At first, it may seem reasonable to let Playwright open the app, click the Google authorization button, choose an account, and approve Google Drive access.
In practice, this is fragile.
It may fail because of:
Google browser automation detection
2-step verification
account security checks
unverified app warnings
consent screen changes
captcha or suspicious login detectionThe goal of this test is to test the application’s Google Drive behavior, not Google’s login page.
So the better test design is:
Prepare a valid Google Drive access token before the test
Inject the token into the browser
Let the SPA call the real Google Drive APIImportant Concept
There are three important values in this flow:
OAuth Client ID / Client Secret
Refresh Token
Access TokenThey are related, but they are not the same thing.
- OAuth Client ID and Client Secret
The OAuth Client ID identifies the Google OAuth app.
The OAuth Client Secret proves that the token exchange request is coming from that OAuth client.
For Playwright testing, the client secret should stay on the test machine or CI server.
Do not put the client secret in:
frontend code
browser localStorage
Playwright test files committed to Git
public repositoriesPlaywright itself does not need the client secret.
The test startup script uses the client secret only to generate a fresh access token.
- Refresh Token
The refresh token represents a Google account that has already authorized the application to access Google Drive.
The refresh token is not used directly to call Google Drive APIs.
Instead, it is used to request a short-lived access token. Google’s OAuth documentation describes this model: store the refresh token for future use, use the access token to access Google APIs, and use the refresh token to obtain a new access token when the previous one expires.
Think of it like this:
refresh_token = long-term authorization
access_token = short-term API token- Access Token
The access token is the token that is actually sent to the Google Drive API.
Example:
Authorization: Bearer ya29.xxxxxThe access token is short-lived, so it should be generated before each test run.
Playwright only needs this access token.
Why Refresh Token Alone Is Not Enough
A refresh token is bound to a specific OAuth client.
When exchanging a refresh token for an access token, Google needs to know:
Which OAuth client is making the request?
Does this OAuth client match the refresh token?
Did the user authorize this OAuth client?That is why the token exchange requires:
client_id
client_secret
refresh_tokenThe response contains:
access_tokenSo the flow is:
client_id + client_secret + refresh_token
→ Google OAuth token endpoint
→ access_tokenThe access token is then passed to Playwright.
Create a Separate OAuth Client for E2E Token Generation
For automated testing, I use a separate OAuth client only for generating E2E test tokens.
Create this E2E OAuth client in the same Google Cloud project as the real application so the requested Drive scopes and OAuth consent configuration match the app being tested.
This keeps the token generation setup separate from the normal application OAuth client.
Go to:
Google Auth Platform
→ Clients
→ Create clientCreate a new OAuth client:
Application type: Web application
Name: Google Drive E2E Token GeneratorAdd this Authorized redirect URI:
https://developers.google.com/oauthplaygroundThis redirect URI is needed because OAuth Playground will be used to generate the refresh token.
After creating the client, copy the following values:
OAuth Client ID
OAuth Client SecretDo not share the client secret.
Get a Refresh Token with OAuth Playground
To generate access tokens automatically, you first need a refresh token.
This is a one-time setup.
Open:
https://developers.google.com/oauthplaygroundClick the gear icon in the upper-right corner.
Use these settings:
OAuth flow: Server-side
Access type: Offline
Force prompt: Consent Screen
Use your own OAuth credentials: enabledEnter the OAuth Client ID and OAuth Client Secret from the E2E token generator client.
Then close the settings panel.
This step is important. OAuth Playground notes that refresh tokens are automatically revoked after 24 hours unless you specify your own application OAuth credentials.
- Select the Google Drive Scope
In OAuth Playground, select the Google Drive scope your test needs.
For limited file access:
https://www.googleapis.com/auth/drive.fileFor read-only access:
https://www.googleapis.com/auth/drive.readonlyFor full Google Drive access:
https://www.googleapis.com/auth/driveUse the smallest scope that supports the test. Google’s Drive API documentation describes drive.file as a scope that lets users choose which files they share with the app, limiting the app’s access compared with broader Drive scopes.
Then click:
Authorize APIsChoose the Google account used for E2E testing and approve the Google Drive permission request.
After authorization, OAuth Playground returns to Step 2.
Click:
Exchange authorization code for tokensYou should see:
access_token
refresh_token
expires_in
scope
token_typeSave the refresh_token.
The refresh token is the long-term value needed by the test machine.
Do not commit it to Git.
Store the Credentials on the Ubuntu Test Machine
On the Ubuntu test machine, create a private environment file:
nano ~/.google-drive-e2e.envAdd:
export GOOGLE_CLIENT_ID="your-e2e-oauth-client-id"
export GOOGLE_CLIENT_SECRET="your-e2e-oauth-client-secret"
export GOOGLE_REFRESH_TOKEN="your-refresh-token"Lock down the file permissions:
chmod 600 ~/.google-drive-e2e.envThis file should exist only on the test machine or CI secret storage.
Generate a Fresh Access Token
Install jq if needed:
sudo apt update
sudo apt install -y jqLoad the environment file:
source ~/.google-drive-e2e.envExchange the refresh token for an access token:
ACCESS_TOKEN=$(curl -s https://oauth2.googleapis.com/token \
-d client_id="$GOOGLE_CLIENT_ID" \
-d client_secret="$GOOGLE_CLIENT_SECRET" \
-d refresh_token="$GOOGLE_REFRESH_TOKEN" \
-d grant_type=refresh_token \
| jq -r .access_token)
echo "$ACCESS_TOKEN"If successful, the output should be a long access token.
It may start with something like:
ya29.Test the Access Token Against Google Drive API
Before using Playwright, test the token directly:
curl -s \
-H "Authorization: Bearer $ACCESS_TOKEN" \
"https://www.googleapis.com/drive/v3/files?pageSize=10&fields=files(id,name,mimeType)" \
| jqIf this returns JSON, the access token works.
Example response:
{
"files": [
{
"id": "abc123",
"name": "example.txt",
"mimeType": "text/plain"
}
]
}Pass the Access Token to Playwright
Export the access token as an environment variable:
export E2E_GOOGLE_ACCESS_TOKEN="$ACCESS_TOKEN"Then Playwright can read:
process.env.E2E_GOOGLE_ACCESS_TOKENPlaywright does not need the refresh token or client secret.
Only the startup script needs those values.
Add E2E Token Support to the SPA
The browser-side app needs a small E2E-only path that accepts the injected token.
For example, during app startup:
const e2eToken = localStorage.getItem('E2E_GOOGLE_ACCESS_TOKEN');
if (e2eToken) {
setGoogleAccessToken(e2eToken);
}The actual function name depends on the application.
The idea is:
If E2E_GOOGLE_ACCESS_TOKEN exists in localStorage
→ skip the Google authorization button
→ treat Google Drive as already authorized
→ use this token for Google Drive API callsThis should only be enabled in a test or development environment.
For example:
if (import.meta.env.MODE === 'e2e') {
const e2eToken = localStorage.getItem('E2E_GOOGLE_ACCESS_TOKEN');
if (e2eToken) {
setGoogleAccessToken(e2eToken);
}
}Do not allow arbitrary token injection in production.
Inject the Token in Playwright
In the Playwright test:
import { test, expect } from '@playwright/test';
test.beforeEach(async ({ page }) => {
const accessToken = process.env.E2E_GOOGLE_ACCESS_TOKEN;
if (!accessToken) {
throw new Error('Missing E2E_GOOGLE_ACCESS_TOKEN');
}
await page.addInitScript((token) => {
localStorage.setItem('E2E_GOOGLE_ACCESS_TOKEN', token);
}, accessToken);
await page.goto('/');
});
test('can open Google Drive feature', async ({ page }) => {
await expect(page.getByText('Google Drive')).toBeVisible();
// Continue with your real test steps here.
});The important part is that page.addInitScript() runs before the SPA scripts execute. Playwright documents that this script is evaluated after the document is created but before the page’s own scripts run.
That allows the SPA to read the token during startup.
Create a Run Script
Create a script named:
run-e2e.shContent:
#!/usr/bin/env bash
set -euo pipefail
source "$HOME/.google-drive-e2e.env"
ACCESS_TOKEN=$(curl -s https://oauth2.googleapis.com/token \
-d client_id="$GOOGLE_CLIENT_ID" \
-d client_secret="$GOOGLE_CLIENT_SECRET" \
-d refresh_token="$GOOGLE_REFRESH_TOKEN" \
-d grant_type=refresh_token \
| jq -r .access_token)
if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" = "null" ]; then
echo "Failed to generate Google access token"
exit 1
fi
export E2E_GOOGLE_ACCESS_TOKEN="$ACCESS_TOKEN"
xvfb-run -a \
--server-args="-screen 0 1920x1080x24 -ac -nolisten tcp +extension RANDR" \
npx playwright test --headedMake it executable:
chmod +x run-e2e.shRun the test:
./run-e2e.shDid this guide save you time?
Support this site