# How to Set Up Google OAuth for Gmail, Calendar, and Drive Integration in Craft-Agents OSS

> Easily set up Google OAuth for Gmail, Calendar, and Drive integration with Craft-Agents OSS. Leverage the built-in PKCE-based OAuth 2.0 for seamless authentication.

- Repository: [Craft Ai Agents/craft-agents-oss](https://github.com/craft-ai-agents/craft-agents-oss)
- Tags: how-to-guide
- Published: 2026-07-03

---

**Craft-Agents OSS provides a built-in PKCE-based OAuth 2.0 implementation that automatically handles authentication flows for Gmail, Calendar, Drive, and other Google APIs through declarative source configuration or programmatic API calls.**

Craft-Agents OSS provides a built-in authentication system that eliminates the need for external OAuth libraries when integrating with Google APIs. The platform supports both declarative configuration through source definitions and programmatic access via the [`google-oauth.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/google-oauth.ts) module. This implementation follows the OAuth 2.0 PKCE pattern to securely authenticate users and maintain long-lived access through refresh tokens.

## Understanding the OAuth Flow Architecture

The Google OAuth implementation in [`packages/shared/src/auth/google-oauth.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/auth/google-oauth.ts) orchestrates the complete authorization flow as implemented in craft-ai-agents/craft-agents-oss from initial request to token refresh. The architecture follows the standard OAuth 2.0 PKCE pattern with specific optimizations for headless and interactive environments.

### PKCE Implementation and Authorization URL Generation

The flow begins with **credential resolution** and **PKCE generation**. When a source configuration specifies `googleOAuthClientId` and `googleOAuthClientSecret`, these values take precedence; otherwise, the system falls back to the environment variables `GOOGLE_OAUTH_CLIENT_ID` and `GOOGLE_OAUTH_CLIENT_SECRET` as defined in lines 25-31 of [`google-oauth.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/google-oauth.ts).

The `startGoogleOAuth` function constructs the authorization URL targeting `https://accounts.google.com/o/oauth2/v2/auth` with the following critical parameters:
- `access_type=offline` to ensure a refresh token is issued
- PKCE challenge derived from a randomly generated verifier
- `state` token for CSRF protection
- Scopes determined by either the `googleService` field or custom `googleScopes` array

### Token Exchange and User Validation

After the user authenticates through the browser, a local HTTP server created by `createCallbackServer` captures the authorization code. The `exchangeCodeForTokens` function then POSTs the code, PKCE verifier, and client credentials to `https://oauth2.googleapis.com/token`, receiving an `access_token`, optional `refresh_token`, and `expires_in` value.

Subsequently, the system validates the authentication by fetching the user's email from `https://www.googleapis.com/oauth2/v2/userinfo`, returning a complete `GoogleOAuthResult` containing the tokens, expiry timestamp, and user identity.

## Configuring Google OAuth Credentials

Craft-Agents OSS supports flexible credential management through source configuration or environment variables, allowing secure deployment across development and production environments.

### Environment Variables vs Source Configuration

You can define credentials at the system level using environment variables:
- `GOOGLE_OAUTH_CLIENT_ID`
- `GOOGLE_OAUTH_CLIENT_SECRET`

Alternatively, provide credentials per-source in the JSON or YAML configuration using `googleOAuthClientId` and `googleOAuthClientSecret` fields. This approach enables multi-tenant scenarios where different sources use distinct Google Cloud projects.

### Scope Selection Strategies

The platform provides two methods for defining OAuth scopes. The **service-based approach** uses the `googleService` field to automatically select predefined scopes for Gmail, Calendar, Drive, Docs, Sheets, YouTube, or Search Console. The **custom scope approach** allows explicit definition via the `googleScopes` array, which the `getGoogleScopes` helper merges with the mandatory `userinfo.email` scope (lines 76-84 of [`google-oauth.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/google-oauth.ts)).

## Source Configuration Examples

Configure Google OAuth through declarative source definitions that the source manager automatically processes when `provider: "google"` is specified.

### Gmail Integration

The following configuration enables Gmail API access using the predefined service scope:

```json
{
  "slug": "my-gmail",
  "provider": "google",
  "api": {
    "baseUrl": "https://gmail.googleapis.com",
    "authType": "oauth",
    "googleService": "gmail",
    "googleOAuthClientId": "YOUR_CLIENT_ID",
    "googleOAuthClientSecret": "YOUR_CLIENT_SECRET"
  }
}

```

The `googleService: "gmail"` field automatically selects the appropriate Gmail scopes from the `GOOGLE_SERVICE_SCOPES` definition in [`google-oauth.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/google-oauth.ts) (lines 40-52).

### Calendar with Custom Scopes

For granular permissions, override the default scopes with specific access rights:

```json
{
  "slug": "my-calendar",
  "provider": "google",
  "api": {
    "baseUrl": "https://calendar.googleapis.com",
    "authType": "oauth",
    "googleScopes": [
      "https://www.googleapis.com/auth/calendar.events.readonly",
      "https://www.googleapis.com/auth/userinfo.email"
    ],
    "googleOAuthClientId": "YOUR_CLIENT_ID",
    "googleOAuthClientSecret": "YOUR_CLIENT_SECRET"
  }
}

```

Custom scopes bypass the predefined service sets while maintaining the automatic inclusion of `userinfo.email` through the `getGoogleScopes` function.

### Drive Access Using Default Service Scopes

The simplest configuration for Google Drive uses the service preset:

```json
{
  "slug": "my-drive",
  "provider": "google",
  "api": {
    "baseUrl": "https://drive.googleapis.com",
    "authType": "oauth",
    "googleService": "drive",
    "googleOAuthClientId": "YOUR_CLIENT_ID",
    "googleOAuthClientSecret": "YOUR_CLIENT_SECRET"
  }
}

```

This configuration automatically requests `https://www.googleapis.com/auth/drive` plus the email verification scope.

## Implementing OAuth Programmatically

For custom tools or dynamic authentication flows, import the OAuth functions directly from `@craft-agents/shared`.

### Using startGoogleOAuth

Invoke the authorization flow programmatically when you need to authenticate outside the standard source configuration:

```typescript
import { startGoogleOAuth } from '@craft-agents/shared/auth/google-oauth';

async function authenticateDrive() {
  const result = await startGoogleOAuth({
    service: 'drive',
    clientId: process.env.GOOGLE_OAUTH_CLIENT_ID,
    clientSecret: process.env.GOOGLE_OAUTH_CLIENT_SECRET,
  });

  if (!result.success) {
    console.error('OAuth failed:', result.error);
    return;
  }

  console.log('Access token:', result.accessToken);
  console.log('Refresh token:', result.refreshToken);
  console.log('User email:', result.email);
}

```

The `GoogleOAuthResult` object includes the client credentials, enabling you to store the complete authentication context for later use.

### Token Refresh Handling

Long-lived integrations require token refresh when the access token expires. The `refreshGoogleToken` function (lines 89-99 of [`google-oauth.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/google-oauth.ts)) reuses the stored client ID, client secret, and refresh token to obtain new credentials without user interaction:

```typescript
import { refreshGoogleToken } from '@craft-agents/shared/auth/google-oauth';

const newTokens = await refreshGoogleToken({
  clientId: storedCredentials.clientId,
  clientSecret: storedCredentials.clientSecret,
  refreshToken: storedCredentials.refreshToken,
});

```

This function handles the POST request to `https://oauth2.googleapis.com/token` with `grant_type=refresh_token` and returns updated token data.

## Key Implementation Files

The Google OAuth system spans several modules in the `packages/shared` directory:

- **[`packages/shared/src/auth/google-oauth.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/auth/google-oauth.ts)** – Core OAuth flow implementation including PKCE generation, token exchange, and refresh logic.

- **[`packages/shared/src/sources/types.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/sources/types.ts)** – Defines the `GoogleService` type and source configuration interfaces (lines 64-70).

- **[`packages/shared/src/config/validators.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/config/validators.ts)** – Zod schema validation for Google-specific configuration fields.

- **[`packages/shared/src/sources/credential-manager.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/sources/credential-manager.ts)** – Extracts OAuth credentials from source configurations and builds authentication contexts.

- **[`packages/shared/src/sources/server-builder.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/sources/server-builder.ts)** – Determines OAuth requirements per source and constructs appropriate HTTP clients with automatic token refresh.

## Summary

- **PKCE-based security**: The implementation uses Proof Key for Code Exchange to secure the OAuth flow without requiring a client secret in the browser.

- **Flexible credential management**: Support for both environment variables (`GOOGLE_OAUTH_CLIENT_ID`, `GOOGLE_OAUTH_CLIENT_SECRET`) and per-source configuration fields.

- **Automatic scope resolution**: The `googleService` field selects predefined scopes for Gmail, Calendar, Drive, and other services, while `googleScopes` allows custom permission definitions.

- **Built-in token refresh**: The `refreshGoogleToken` function automatically handles access token renewal using stored refresh tokens.

- **Source manager integration**: Declarative configuration with `provider: "google"` automatically triggers the OAuth flow and maintains authentication state.

## Frequently Asked Questions

### What is the difference between using googleService and googleScopes?

The `googleService` field selects predefined scope sets optimized for specific Google APIs like Gmail or Drive, automatically including necessary permissions plus `userinfo.email`. The `googleScopes` field allows complete customization of OAuth permissions, overriding any predefined service scopes while maintaining the email verification requirement. Both approaches are validated through `getGoogleScopes` in [`packages/shared/src/auth/google-oauth.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/auth/google-oauth.ts).

### How does token refresh work in Craft-Agents OSS?

When an access token expires, the system calls `refreshGoogleToken` (lines 89-99 of [`google-oauth.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/google-oauth.ts)) with the stored client credentials and refresh token. This function exchanges the refresh token for a new access token at `https://oauth2.googleapis.com/token` without requiring user interaction. The source manager in [`server-builder.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/server-builder.ts) automatically handles this refresh when constructing API clients.

### Can I use environment variables instead of hardcoding credentials?

Yes. If you omit `googleOAuthClientId` and `googleOAuthClientSecret` from the source configuration, the credential manager automatically falls back to the `GOOGLE_OAUTH_CLIENT_ID` and `GOOGLE_OAUTH_CLIENT_SECRET` environment variables. This approach is recommended for production deployments to keep sensitive credentials out of configuration files.

### What happens if the OAuth callback fails or is interrupted?

The `startGoogleOAuth` function launches a local HTTP server via `createCallbackServer` to capture the authorization code. If the callback fails or the user closes the browser, the function returns a `GoogleOAuthResult` with `success: false` and an error message describing the failure. Your application should handle this case by logging the error and optionally prompting the user to retry the authentication flow.