# How the OAuth Flow Is Implemented for Google, Slack, and Microsoft Integrations in Craft-Agents OSS

> Explore the OAuth flow implementation in Craft-Agents OSS for Google, Slack, and Microsoft integrations. Learn about PKCE, HTTP Basic auth, and a shared callback server.

- Repository: [Craft Docs/craft-agents-oss](https://github.com/lukilabs/craft-agents-oss)
- Tags: how-to-guide
- Published: 2026-04-18

---

**Craft-Agents OSS implements a unified OAuth 2.0 architecture with provider-specific adaptations for Google, Slack, and Microsoft, using PKCE for Google and Microsoft, HTTP Basic authentication for Slack, and a shared local callback server to capture authorization codes across all three providers.**

The `lukilabs/craft-agents-oss` repository provides a reusable authentication layer that abstracts the differences between these three major identity providers while maintaining strict type safety and security best practices. The implementation lives in the `packages/shared/src/auth/` directory and supports complete token lifecycles from initial authorization through refresh.

## Unified OAuth Architecture Overview

All three integrations follow an eight-step flow that balances shared infrastructure with provider-specific security requirements:

| Step | Description | Implementation |
|------|-------------|----------------|
| **1. Build Auth URL** | Provider-specific scopes, client IDs, and PKCE parameters (Google/Microsoft) or HTTP-Basic preparation (Slack) are configured. | `prepareGoogleOAuth`, `prepareSlackOAuth`, `prepareMicrosoftOAuth` |
| **2. Open Browser** | Cross-platform browser window launches automatically. | `openUrl` in [`shared/src/utils/open-url.ts`](https://github.com/lukilabs/craft-agents-oss/blob/main/shared/src/utils/open-url.ts) |
| **3. Local Callback Server** | HTTP server listens on `localhost` (or receives relayed traffic for Slack) to capture the authorization code. | `createCallbackServer` in [`shared/src/auth/callback-server.ts`](https://github.com/lukilabs/craft-agents-oss/blob/main/shared/src/auth/callback-server.ts) |
| **4. State Verification** | CSRF protection via `state` parameter validation; errors propagated immediately. | Handled within `startGoogleOAuth`, `startSlackOAuth`, `startMicrosoftOAuth` |
| **5. Token Exchange** | POST to provider token endpoint returns access token, refresh token, and expiry. | `exchangeCodeForTokens` (provider-specific variants) |
| **6. User Identity** | Email or workspace name retrieved via provider-specific "who-am-I" endpoints. | `getUserEmail` (Google/Microsoft) or team extraction (Slack) |
| **7. Typed Result** | Strongly-typed result object containing credentials and metadata. | `GoogleOAuthResult`, `SlackOAuthResult`, `MicrosoftOAuthResult` |
| **8. Token Refresh** | Silent refresh using stored refresh tokens when access tokens expire. | `refreshGoogleToken`, `refreshSlackToken`, `refreshMicrosoftToken` |

## Google OAuth Implementation

The Google integration in [`packages/shared/src/auth/google-oauth.ts`](https://github.com/lukilabs/craft-agents-oss/blob/main/packages/shared/src/auth/google-oauth.ts) follows the standard OAuth 2.0 Authorization Code flow with PKCE extension, suitable for native applications that cannot securely store client secrets.

### Configuration and PKCE Setup

The implementation requires `GOOGLE_OAUTH_CLIENT_ID` and `GOOGLE_OAUTH_CLIENT_SECRET` environment variables (lines 29-31). Before initiating the flow, `generatePKCE` creates a cryptographically random `code_verifier` and its SHA256 hash `code_challenge` (S256 method).

Scopes are service-specific via `GOOGLE_SERVICE_SCOPES`, with `userinfo.email` always appended via `getGoogleScopes` to ensure user identification.

### Authorization and Token Exchange

The `startGoogleOAuth` function (lines 82-85) orchestrates the flow:

1. **Authorization URL Construction**: Includes `client_id`, `redirect_uri`, `response_type=code`, `scope`, `state`, `code_challenge`, `code_challenge_method=S256`, `access_type=offline`, and `prompt=consent` to force refresh token issuance.

2. **Callback Server**: `createCallbackServer` starts a local HTTP server (default port 6477) to receive the redirect.

3. **Code Exchange**: `exchangeCodeForTokens` POSTs to `https://oauth2.googleapis.com/token` with the PKCE verifier and client secret, returning `access_token`, `refresh_token`, and `expires_in`.

4. **User Email**: `getUserEmail` calls `https://www.googleapis.com/oauth2/v2/userinfo` to retrieve the authenticated email address.

### Google OAuth Example

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

async function loginGmail() {
  const result = await startGoogleOAuth({ service: 'gmail' });
  if (!result.success) {
    console.error('Google OAuth failed:', result.error);
    return;
  }
  console.log('Access token:', result.accessToken);
  console.log('Refresh token:', result.refreshToken);
  console.log('User email:', result.email);
}

```

The result type is `GoogleOAuthResult` (line 94), containing the tokens, expiry timestamp, email, and client credentials for future refresh operations.

## Slack OAuth Implementation

The Slack integration in [`packages/shared/src/auth/slack-oauth.ts`](https://github.com/lukilabs/craft-agents-oss/blob/main/packages/shared/src/auth/slack-oauth.ts) differs significantly from Google and Microsoft because Slack uses a **user-scope OAuth flow** with HTTP Basic authentication rather than PKCE.

### HTTP Basic Authentication

Slack requires `SLACK_OAUTH_CLIENT_ID` and `SLACK_OAUTH_CLIENT_SECRET` as mandatory environment variables (lines 27-28). Unlike Google, Slack does not use PKCE; instead, the client credentials are encoded using HTTP Basic auth (`base64(client_id:client_secret)`) during the token exchange.

Scopes are defined in `SLACK_SERVICE_SCOPES` and passed as `user_scope` (not `scope`) in the authorization URL via `getSlackScopes`.

### Cloudflare Relay for HTTPS Callback

Slack mandates HTTPS redirect URIs, which poses a challenge for local development. The implementation solves this via a Cloudflare relay:

- The `redirect_uri` is set to `https://agents.craft.do/auth/slack/callback` (lines 58-61)
- This endpoint forwards the authorization code to the local HTTP server running on localhost
- The local server is still created via `createCallbackServer`, maintaining architectural consistency with the other providers

### Token Exchange and Workspace Info

The `exchangeCodeForTokens` function POSTs to `https://slack.com/api/oauth.v2.access` with the Basic auth header. The response contains:
- `authed_user.access_token` (the user token)
- `team` object with `id` and `name`
- `authed_user.id`

The `exchangeSlackOAuth` function returns the team name as the identifier (since Slack workspace access is the primary authorization unit), wrapping everything in `SlackOAuthResult` (line 82).

### Slack OAuth Example

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

async function loginSlack() {
  const result = await startSlackOAuth({ service: 'full' });
  if (!result.success) {
    console.error('Slack OAuth failed:', result.error);
    return;
  }
  console.log('User token:', result.accessToken);
  console.log('Workspace:', result.teamName, `(ID ${result.teamId})`);
}

```

## Microsoft OAuth Implementation

The Microsoft integration in [`packages/shared/src/auth/microsoft-oauth.ts`](https://github.com/lukilabs/craft-agents-oss/blob/main/packages/shared/src/auth/microsoft-oauth.ts) follows a PKCE-based flow similar to Google but with Microsoft Graph-specific endpoints and scope conventions.

### Client-Only Authentication (PKCE)

Microsoft OAuth in Craft-Agents uses **PKCE without a client secret**, making it suitable for native applications. Only `MICROSOFT_OAUTH_CLIENT_ID` is required (line 32); the PKCE verifier serves as the security mechanism instead of a shared secret.

The `generatePKCE` function creates the verifier and S256 challenge identically to the Google implementation.

### Microsoft Graph Integration

Scopes are service-specific via `MICROSOFT_SERVICE_SCOPES`, with mandatory additions in `getMicrosoftScopes`:
- `User.Read` (for user profile access)
- `offline_access` (to receive refresh tokens)

The authorization URL includes `response_mode=query` and `prompt=consent` alongside standard PKCE parameters.

Token exchange POSTs to `https://login.microsoftonline.com/common/oauth2/v2.0/token` with the PKCE verifier. The `access_token` is then used to call Microsoft Graph at `https://graph.microsoft.com/v1.0/me`.

User email resolution prefers the `mail` property, falling back to `userPrincipalName` if the primary email is not available.

### Microsoft OAuth Example

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

async function loginOutlook() {
  const result = await startMicrosoftOAuth({ service: 'outlook' });
  if (!result.success) {
    console.error('Microsoft OAuth failed:', result.error);
    return;
  }
  console.log('Access token:', result.accessToken);
  console.log('User email/UPN:', result.email);
}

```

The result conforms to `MicrosoftOAuthResult` (line 100), containing tokens, expiry, and the resolved email address.

## Shared Infrastructure Components

### The Local Callback Server

All three providers rely on `createCallbackServer` in [`packages/shared/src/auth/callback-server.ts`](https://github.com/lukilabs/craft-agents-oss/blob/main/packages/shared/src/auth/callback-server.ts) (lines 57-89) to capture the OAuth redirect:

- **Port Selection**: Iterates from port 6477 upward for up to 100 attempts (`START_PORT` / `MAX_PORT_ATTEMPTS`)
- **Request Handling**: Parses query strings to extract `code` and `error` parameters
- **User Experience**: Generates HTML success/failure pages via `generateCallbackPage` to provide clear feedback to the user
- **Deeplink Support**: When `deeplinkUrl` is provided, the success page redirects back to the Craft-Agents application

### Cross-Platform Browser Opening

The `openUrl` utility in [`packages/shared/src/utils/open-url.ts`](https://github.com/lukilabs/craft-agents-oss/blob/main/packages/shared/src/utils/open-url.ts) handles platform detection to launch the default browser consistently across macOS, Windows, and Linux environments.

## Summary

- **Unified Architecture**: All three providers use the same eight-step flow built on `createCallbackServer`, with provider-specific adaptations for security mechanisms.
- **PKCE for Google and Microsoft**: Both implementations use PKCE (RFC 7636) to secure the authorization code flow, with Google requiring a client secret while Microsoft operates client-only.
- **Slack HTTP Basic Auth**: Slack substitutes PKCE with HTTP Basic authentication and requires a Cloudflare HTTPS relay to satisfy redirect URI requirements.
- **Shared Infrastructure**: The [`callback-server.ts`](https://github.com/lukilabs/craft-agents-oss/blob/main/callback-server.ts) module provides the local HTTP listener, while [`open-url.ts`](https://github.com/lukilabs/craft-agents-oss/blob/main/open-url.ts) handles cross-platform browser launching for all providers.
- **Type-Safe Results**: Each provider returns a strongly-typed result object (`GoogleOAuthResult`, `SlackOAuthResult`, `MicrosoftOAuthResult`) containing tokens, expiry, and user identity.

## Frequently Asked Questions

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

The Google implementation uses PKCE (Proof Key for Code Exchange) with a client secret during token exchange, while Slack uses HTTP Basic authentication with base64-encoded credentials and does not implement PKCE. Additionally, Google communicates directly with localhost, whereas Slack requires a Cloudflare HTTPS relay to handle the redirect URI.

### Why does the Slack OAuth flow require a Cloudflare relay instead of direct localhost communication?

Slack's OAuth 2.0 implementation mandates HTTPS redirect URIs for security reasons, which prevents direct communication with a local HTTP server running on `localhost`. The Craft-Agents implementation solves this by redirecting to `https://agents.craft.do/auth/slack/callback`, which then forwards the authorization code to the local callback server running via `createCallbackServer`.

### How does the callback server handle concurrent OAuth attempts from different providers?

The `createCallbackServer` function in [`packages/shared/src/auth/callback-server.ts`](https://github.com/lukilabs/craft-agents-oss/blob/main/packages/shared/src/auth/callback-server.ts) attempts to bind to ports starting at 6477, iterating up to 100 times to find an available port. Each OAuth flow instance creates its own server instance on a unique available port, allowing concurrent authentication attempts to operate independently without port conflicts.

### Is PKCE required for all OAuth providers in the Craft-Agents implementation?

No, PKCE is only required for Google and Microsoft integrations. The Google implementation uses PKCE with an additional client secret, while Microsoft uses PKCE without a client secret (client-only authentication). The Slack implementation deliberately omits PKCE in favor of HTTP Basic authentication during the token exchange phase.