How to Connect Claude Code to Google Drive (with OAuth)
๐ค AI Agent? You can point your AI agent at this article and it can follow the steps to connect automatically. Everything it needs is here: the API endpoints, request/response formats, scopes, and working code samples. The TapAuth API is two calls โ
POST https://tapauth.ai/api/v1/grantsto create a grant, thenGET https://tapauth.ai/api/v1/token/{id}(with Bearer auth) to retrieve the access token. No API key needed โ your agent can follow the code examples below end-to-end.
Claude Code excels at working with files โ reading code, analyzing data, writing documentation. But all of that capability is limited to your local filesystem. The moment you want Claude Code to read a Google Doc, search through shared Drive folders, or pull data from a spreadsheet, it needs a Google Drive OAuth token. And Google's OAuth flow is built for web apps with browsers, not agents in terminals.
This is what TapAuth solves. TapAuth is the token layer for AI agents โ one API call, and your agent gets a valid, scoped, user-approved Google Drive token. No OAuth implementation. No redirect servers. No token storage headaches. Your agent asks for a token and gets one.
This guide covers the full manual Google Drive OAuth flow, then the TapAuth approach. If you've read our Claude Code + Gmail guide, you'll recognize some of Google's OAuth patterns โ but Drive adds its own layer of complexity on top.
Why Google Drive OAuth is harder than you'd expect
Google Drive shares the same OAuth infrastructure as Gmail, but the Drive-specific challenges stack on top of the standard Google OAuth pain:
- Scope granularity creates a paradox. Google Drive has over a dozen scopes ranging from
drive.file(only files your app created) todrive(full access to everything). The narrow scopes are safe but severely limit what your agent can do โdrive.filemeans your agent can't read documents the user already has. The broad scopes trigger Google's verification requirements, adding weeks to your timeline. - File type complexity. Google Drive isn't just a file store โ Google Docs, Sheets, and Slides are native formats that require export conversion. When your agent reads a Doc, it gets a file ID that requires a separate export call to get actual content. A PDF or image requires a download call with a different endpoint. Your agent needs to handle at least three different retrieval patterns.
- Shared Drive permissions are a separate system. Personal Drive and Shared Drives (formerly Team Drives) have different permission models. API calls that work on personal files silently return empty results for Shared Drive files unless you pass
supportsAllDrives: trueandincludeItemsFromAllDrives: true. This is one of the most common bugs in Drive integrations. - The same one-time refresh token problem. Like Gmail, Google gives you the refresh token only on the first authorization. Miss it, and you're re-prompting the user. For agents that run unattended, losing the refresh token means the agent stops working the next time the access token expires โ at 3 AM, with no user around to re-authorize.
- Rate limits are per-user, not per-app. Google Drive API has a 12,000 requests per minute per user limit โ which sounds generous until your agent starts recursively listing folder contents. A deep folder scan can burn through the quota fast, and the 403 errors look identical to permission errors.
The pattern is the same as with every OAuth provider: the authentication infrastructure is harder than the actual integration. Your agent wants to read a document โ you're building a token management system.
What the manual Google Drive OAuth flow looks like
This builds on the same Google OAuth infrastructure as the Gmail flow, but with Drive-specific handling for file types and exports.
import { google } from 'googleapis';
// Step 1: Create OAuth2 client (same as Gmail)
const oauth2Client = new google.auth.OAuth2(
process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_CLIENT_SECRET,
'http://localhost:3000/callback'
);
// Step 2: Generate authorization URL with Drive scopes
const authUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: [
'https://www.googleapis.com/auth/drive.readonly',
// Or drive.file for minimal access โ but agent can only see files it created
],
prompt: 'consent', // Force consent to get refresh token
});
// Step 3: Same redirect server dance as Gmail
// (Omitted โ see our Claude Code + Gmail guide for the full server setup)
// Step 4: After token exchange, use the Drive API
const drive = google.drive({ version: 'v3', auth: oauth2Client });
// List files โ but watch out for Shared Drives
async function listFiles(query: string) {
const res = await drive.files.list({
q: query,
fields: 'files(id, name, mimeType, modifiedTime)',
supportsAllDrives: true, // Required for Shared Drive files
includeItemsFromAllDrives: true, // Also required โ miss this and you get silent empty results
pageSize: 50,
});
return res.data.files;
}
// Read a file โ but the method depends on the file type
async function readFile(fileId: string, mimeType: string) {
if (mimeType === 'application/vnd.google-apps.document') {
// Google Docs require export, not download
const res = await drive.files.export({
fileId,
mimeType: 'text/plain', // or text/html, application/pdf
});
return res.data;
} else if (mimeType === 'application/vnd.google-apps.spreadsheet') {
// Sheets export as CSV
const res = await drive.files.export({
fileId,
mimeType: 'text/csv',
});
return res.data;
} else {
// Binary files (PDFs, images) use download
const res = await drive.files.get(
{ fileId, alt: 'media' },
{ responseType: 'arraybuffer' }
);
return res.data;
}
}
// Handle token refresh (access tokens expire every hour)
oauth2Client.on('tokens', (tokens) => {
if (tokens.refresh_token) {
saveRefreshTokenToEncryptedStore(tokens.refresh_token);
}
});
Even with Google's official SDK handling much of the HTTP plumbing, you're still dealing with: redirect server setup, refresh token management, Shared Drive flags, three different file retrieval patterns based on MIME type, and the ever-present risk of losing that one-time refresh token. And this is the read-only version โ writing and uploading files adds more complexity.
The TapAuth approach: same two API calls
TapAuth handles Google's OAuth complexity the same way it handles every provider โ your agent makes two API calls and gets a working token. No redirect server. No refresh token management. No Shared Drive gotchas in the auth layer.
// Step 1: Create a grant โ tell TapAuth what you need
const grantResponse = await fetch(
'https://tapauth.ai/api/v1/grants',
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.TAPAUTH_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
provider: 'google',
scopes: ['drive.readonly'],
}),
}
);
const { grant_id, grant_secret, approve_url } = await grantResponse.json();
// Step 2: The user approves at the approve_url
console.log(`Approve access: ${approve_url}`);
// Step 3: Retrieve the token (poll until approved)
const tokenResponse = await fetch(
`https://tapauth.ai/api/v1/token/${grant_id}`,
{
headers: { 'Authorization': `Bearer ${grant_secret}` },
}
);
const { access_token } = await tokenResponse.json();
// Now use the token directly with Google Drive API
// List recent documents
const listResponse = await fetch(
'https://www.googleapis.com/drive/v3/files?' + new URLSearchParams({
q: "mimeType='application/vnd.google-apps.document'",
fields: 'files(id,name,modifiedTime)',
supportsAllDrives: 'true',
includeItemsFromAllDrives: 'true',
pageSize: '10',
orderBy: 'modifiedTime desc',
}),
{
headers: { Authorization: `Bearer ${access_token}` },
}
);
const { files } = await listResponse.json();
// Read a Google Doc as plain text
const docId = files[0].id;
const docResponse = await fetch(
`https://www.googleapis.com/drive/v3/files/${docId}/export?mimeType=text/plain`,
{
headers: { Authorization: `Bearer ${access_token}` },
}
);
const documentContent = await docResponse.text();
Two API calls to get the token, then standard Drive API calls with it. TapAuth handles the OAuth consent flow, token exchange, and refresh cycle. When the access token expires in an hour, your agent calls the token endpoint again and gets a fresh one โ TapAuth refreshes it automatically behind the scenes.
The Drive-specific complexity (file types, Shared Drives, export formats) still exists in the API calls โ that's Google Drive, not auth. But the authentication complexity is gone. And when you need to add Slack access tomorrow, it's the same two API calls with a different provider name.
What you can build with Claude Code + Google Drive + TapAuth
Google Drive is where most teams keep their knowledge. With authentication handled, Claude Code gets access to all of it:
- Document summarizer: "Read the Q3 product roadmap doc and give me the key milestones and owners"
- Research assistant: "Search my Drive for anything related to the API migration and compile a summary of decisions made"
- Spreadsheet analyzer: "Pull the latest sales data from the revenue spreadsheet and tell me which regions are trending up"
- Documentation updater: "Read the current API docs in Drive and flag any endpoints that don't match our actual implementation"
- Meeting notes processor: "Find all meeting notes from this week, extract action items, and list who's responsible for each"
Each of these is Drive API calls plus Claude Code's analytical abilities. The hard part โ getting a valid, scoped, auto-refreshing OAuth token โ is one API call via TapAuth.
Scopes and permissions: what to request for Google Drive
Google Drive scopes range from very narrow to very broad. Choose carefully:
| Scope | What it allows | When to use it |
|---|---|---|
drive.file | Only files created by your app | Writing new docs โ but can't read existing files |
drive.readonly | Read all files and metadata | Document search, summaries, analysis (recommended start) |
drive.metadata.readonly | File names and metadata only, no content | File discovery, folder structure mapping |
drive | Full read/write access | Creating and editing documents (use sparingly) |
Start with drive.readonly for most agent use cases. Your agent can search, read, and analyze everything without the risk of accidentally modifying or deleting files. Upgrade to drive only when your agent needs to create or edit documents, and consider using drive.file for write operations to limit the blast radius.
TapAuth lets you configure scopes per grant. Your research agent gets read-only access, your documentation agent gets write access to a specific folder โ different permissions for different agents, same simple API.
Stop rebuilding Google OAuth for every agent
If you've already implemented Google OAuth for Gmail, you might think Drive is easy โ same provider, same infrastructure. It is the same infrastructure, and it's the same pain: redirect servers, refresh tokens, token storage, expiry handling. You're just doing it again for a different set of scopes.
TapAuth means you implement OAuth zero times. Connect Claude Code to Google Drive the same way you'd connect ChatGPT to Slack or Cursor to GitHub โ two API calls, and your agent has a working token.
Get started โ connect Claude Code to Google Drive in under five minutes. No client secrets in your agent code. No refresh token management. Just tokens when your agent needs them.