# How Craft Agents OSS Manages OAuth Flows for Google, Slack, and Microsoft Integrations

> Learn how Craft Agents OSS manages OAuth flows for Google, Slack, and Microsoft integrations using a unified, type-safe architecture, PKCE, and a shared callback server for seamless token exchange.

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

---

**Craft Agents OSS implements a unified, type-safe OAuth 2.0 architecture that uses PKCE for Google and Microsoft, a Cloudflare relay for Slack's HTTPS requirements, and a shared callback server to handle token exchange and automatic credential persistence.**

Craft Agents OSS provides a consistent developer experience for authenticating with third-party providers through a modular OAuth 2.0 implementation. The codebase in `craft-ai-agents/craft-agents-oss` abstracts provider-specific differences—such as PKCE requirements and redirect URI constraints—into reusable components while maintaining type safety across Google, Slack, and Microsoft integrations.

## Unified OAuth Architecture

The OAuth flow management in Craft Agents OSS follows a standardized three-phase pattern regardless of provider. Each integration implements **preparation**, **callback handling**, and **token exchange** through provider-specific modules that share common infrastructure.

The core components include:

- **OAuth preparation** – Functions like `prepareGoogleOAuth`, `prepareSlackOAuth`, and `prepareMicrosoftOAuth` build authorization URLs, generate PKCE verifier/challenge pairs (where required), and create CSRF-state tokens.
- **Callback server** – The `createCallbackServer` function in [`packages/shared/src/auth/callback-server.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/auth/callback-server.ts) creates a temporary local HTTP server that receives provider redirects and resolves a promise with the authorization code.
- **Token exchange** – Provider-specific `exchangeCodeForTokens` functions POST to respective token endpoints and normalize responses into `{accessToken, refreshToken, expiresAt}`.
- **Credential management** – The `SourceCredentialManager` in [`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) persists tokens and handles automatic refresh.

## Google OAuth Flow Implementation

The Google integration utilizes a **PKCE-enabled** flow suitable for public desktop clients. Located 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), this implementation supports both secret-less operation and traditional client-secret authentication when configured.

Key characteristics include:

- **PKCE generation** – The flow generates a `code_challenge` and `code_verifier` using `generatePKCE` to prevent authorization code interception.
- **Predefined scopes** – Service-specific scope sets are stored in `GOOGLE_SERVICE_SCOPES`, covering Gmail, Calendar, Drive, and other Google services.
- **Token endpoint** – Exchanges codes at `https://oauth2.googleapis.com/token`.
- **User identification** – Fetches the user's email from `https://www.googleapis.com/oauth2/v2/userinfo`.

To initiate authentication, call `startGoogleOAuth` with either a service identifier or custom scopes:

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

// Authenticate for Gmail using predefined scopes
async function authGoogleGmail(): Promise<GoogleOAuthResult> {
  return await startGoogleOAuth({ service: 'gmail' });
}

// Authenticate with custom spreadsheet permissions
async function authGoogleSheets(): Promise<GoogleOAuthResult> {
  return await startGoogleOAuth({
    scopes: ['https://www.googleapis.com/auth/spreadsheets.readonly'],
  });
}

```

The returned `GoogleOAuthResult` contains `accessToken`, optional `refreshToken`, `expiresAt`, the user's `email`, and client credentials for subsequent refresh operations.

## Slack OAuth Flow Implementation

Slack's integration diverges from the PKCE pattern and instead uses a **user-token flow** with a Cloudflare relay to handle HTTPS requirements. The implementation resides in [`packages/shared/src/auth/slack-oauth.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/auth/slack-oauth.ts), with relay utilities in [`packages/shared/src/auth/oauth-relay.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/auth/oauth-relay.ts).

Distinctive aspects include:

- **User-scope parameter** – Uses `user_scope` rather than `scope` to obtain tokens that act on behalf of the authenticated user rather than a bot.
- **No PKCE** – Slack does not implement PKCE for this flow.
- **HTTPS redirect handling** – Because Slack requires HTTPS redirect URIs, the flow uses `wrapPreparedOAuthFlowForRelay` to redirect through `https://agents.craft.do/auth/slack/callback`, which forwards to the local HTTP callback server.
- **State envelope** – The `encodeOAuthRelayState` function wraps the OAuth state in a signed envelope containing a `returnTo` URL to prevent CSRF attacks.

Authentication is initiated through `startSlackOAuth`:

```typescript
import { startSlackOAuth, SlackOAuthResult } from '@/shared/auth/slack-oauth';

// Full workspace access
async function authSlackFull(): Promise<SlackOAuthResult> {
  return await startSlackOAuth({ service: 'full' });
}

// Limited to messaging permissions only
async function authSlackMessaging(): Promise<SlackOAuthResult> {
  return await startSlackOAuth({ service: 'messaging' });
}

```

The `SlackOAuthResult` includes `accessToken`, optional `refreshToken` (when token rotation is enabled), `teamId`, `teamName`, and `userId`.

## Microsoft OAuth Flow Implementation

Microsoft's integration follows a PKCE-enabled pattern similar to Google but targets the Microsoft Graph API. The source code in [`packages/shared/src/auth/microsoft-oauth.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/auth/microsoft-oauth.ts) handles both personal and organizational accounts through the `common` tenant endpoint.

Implementation details:

- **PKCE support** – Uses PKCE for public clients, eliminating the need for client secrets in desktop environments.
- **Common tenant endpoint** – Authenticates both personal Microsoft accounts and Azure AD work accounts via `https://login.microsoftonline.com/common/oauth2/v2.0/token`.
- **Required scopes** – Always includes `User.Read` and `offline_access` alongside service-specific scopes defined in `MICROSOFT_SERVICE_SCOPES`.
- **User profile** – Retrieves email via `https://graph.microsoft.com/v1.0/me`.

Invoke the flow using `startMicrosoftOAuth`:

```typescript
import { startMicrosoftOAuth, MicrosoftOAuthResult } from '@/shared/auth/microsoft-oauth';

// Outlook mail access
async function authMicrosoftOutlook(): Promise<MicrosoftOAuthResult> {
  return await startMicrosoftOAuth({ service: 'outlook' });
}

// Custom Microsoft Graph scopes
async function authMicrosoftTasks(): Promise<MicrosoftOAuthResult> {
  return await startMicrosoftOAuth({
    scopes: ['https://graph.microsoft.com/Tasks.ReadWrite'],
  });
}

```

The resulting `MicrosoftOAuthResult` contains `accessToken`, `refreshToken`, `expiresAt`, and the authenticated user's `email`.

## Shared Infrastructure Components

Three provider-agnostic utilities support all OAuth flows in Craft Agents OSS:

**Callback Server** – Implemented in [`packages/shared/src/auth/callback-server.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/auth/callback-server.ts), the `createCallbackServer` function launches a temporary HTTP listener on a local port. It renders a success or failure HTML page to the user and resolves a promise with the query parameters (`code` and `state`) received from the provider's redirect.

**OAuth Relay** – Defined in [`packages/shared/src/auth/oauth-relay.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/auth/oauth-relay.ts), this component handles Slack's HTTPS requirement. The `encodeOAuthRelayState` function creates a signed envelope for the state parameter, while `wrapPreparedOAuthFlowForRelay` rewrites the redirect URI to the Cloudflare relay endpoint.

**Credential Manager** – The `SourceCredentialManager` class in [`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) persists OAuth credentials securely and automatically refreshes expired tokens using provider-specific refresh functions: `refreshGoogleToken`, `refreshSlackToken`, and `refreshMicrosoftToken`.

## End-to-End Flow Execution

When a user creates a source requiring OAuth, the application executes a consistent sequence across all providers:

1. **Configuration validation** – Checks for required client IDs and secrets using `isGoogleOAuthConfigured`, `isSlackOAuthConfigured`, or `isMicrosoftOAuthConfigured`.
2. **Server initialization** – Creates a callback server via `createCallbackServer` to obtain a local `redirect_uri`.
3. **URL construction** – Builds the provider-specific authorization URL with PKCE parameters (Google/Microsoft) or relay state (Slack).
4. **Browser launch** – Opens the user's default browser using the cross-platform `openUrl` utility.
5. **Callback handling** – Awaits the promise resolution from the callback server containing the authorization code.
6. **Token exchange** – Validates the CSRF `state` and exchanges the code for tokens via the provider's token endpoint.
7. **Persistence** – Stores the resulting credentials via `SourceCredentialManager` for automatic signing of subsequent API requests.

This architecture keeps provider-specific logic encapsulated in the individual `*oauth.ts` modules while allowing the higher-level source creation logic to remain provider-agnostic.

## Summary

- Craft Agents OSS unifies OAuth 2.0 flows for Google, Slack, and Microsoft through a modular architecture in `packages/shared/src/auth/`.
- **Google** and **Microsoft** use PKCE-enabled flows without requiring client secrets, while **Slack** uses a user-token flow with a Cloudflare relay to handle HTTPS redirects.
- The `createCallbackServer` function provides a temporary local HTTP listener for all providers to capture authorization codes.
- Provider-specific modules handle token exchange and refresh (`exchangeCodeForTokens`, `refreshGoogleToken`, etc.), while the `SourceCredentialManager` handles persistence and automatic refresh.
- All flows return strongly-typed results (`GoogleOAuthResult`, `SlackOAuthResult`, `MicrosoftOAuthResult`) containing access tokens, refresh tokens, and user identifiers.

## Frequently Asked Questions

### How does Craft Agents OSS handle Slack's requirement for HTTPS redirect URIs?

Since Slack requires HTTPS redirect URIs but the application runs a local HTTP server, Craft Agents OSS uses a Cloudflare relay at `https://agents.craft.do/auth/slack/callback`. The `wrapPreparedOAuthFlowForRelay` function in [`packages/shared/src/auth/oauth-relay.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/auth/oauth-relay.ts) encodes the local callback URL and CSRF state into a signed envelope. When Slack redirects to the relay, it forwards the request to the local callback server, allowing the flow to complete without local HTTPS setup.

### What is the difference between the Google and Slack OAuth implementations in Craft Agents OSS?

The Google 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) uses PKCE (Proof Key for Code Exchange) with `code_challenge` and `code_verifier` parameters to secure the authorization code flow, making it suitable for public clients without client secrets. The Slack implementation in [`packages/shared/src/auth/slack-oauth.ts`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/packages/shared/src/auth/slack-oauth.ts) does not use PKCE; instead, it uses a `user_scope` parameter and requires the Cloudflare relay to handle HTTPS redirects. Additionally, Slack's state parameter is wrapped in a signed envelope to include return URL information.

### How are OAuth tokens refreshed automatically in Craft Agents OSS?

The `SourceCredentialManager` in [`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) stores refresh tokens alongside access tokens. When an access token expires, the manager calls provider-specific refresh functions—`refreshGoogleToken`, `refreshSlackToken`, or `refreshMicrosoftToken`—to exchange the refresh token for a new access token. This process is transparent to the user and ensures continuous API access without re-authentication.

### Can custom OAuth scopes be requested for Microsoft and Google integrations?

Yes. While Craft Agents OSS provides predefined scopes for common services (accessed via the `service` parameter), both `startGoogleOAuth` and `startMicrosoftOAuth` accept a custom `scopes` array. For example, you can request specific Microsoft Graph permissions like `Tasks.ReadWrite` or Google Drive scopes by passing them directly to the initialization function, overriding the default service-specific scopes.