# How to Integrate with OAuth Providers like Google and Microsoft in Thunderbolt

> Integrate Google and Microsoft OAuth in Thunderbolt. Leverage its provider-agnostic layer, core engine, and React hook for seamless authentication and automated PKCE, state, and redirects.

- Repository: [Thunderbird/thunderbolt](https://github.com/thunderbird/thunderbolt)
- Tags: how-to-guide
- Published: 2026-04-19

---

**Thunderbolt provides a provider-agnostic OAuth layer that unifies Google and Microsoft authentication through adapter modules, a core engine, and a React hook that handles PKCE, state management, and cross-platform redirects automatically.**

The Thunderbird Thunderbolt codebase implements a modular OAuth architecture that abstracts provider differences while preserving platform-specific optimizations for web, mobile, and desktop environments. Whether you are building a Tauri-based desktop client or a browser-based interface, the same `useOAuthConnect` hook orchestrates the complete flow from authorization to credential storage.

## Architecture Overview

Thunderbolt’s OAuth implementation is organized into three distinct layers that separate provider logic from platform concerns:

| Layer | Responsibility | Key Files |
|------|----------------|-----------|
| **Provider-specific adapters** | Retrieve provider config, build the auth URL, exchange the authorization code for tokens, and fetch user info. | [`src/integrations/google/auth.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/integrations/google/auth.ts) & [`src/integrations/microsoft/auth.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/integrations/microsoft/auth.ts) |
| **Core OAuth engine** | Defines common types, delegates to the adapters, and decides which redirect strategy to use (web → redirect, Tauri → loopback/server). | [`src/lib/auth.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/lib/auth.ts), [`src/lib/oauth-redirect.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/lib/oauth-redirect.ts), [`src/lib/oauth-loopback.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/lib/oauth-loopback.ts) |
| **UI hook** | Provides a React hook (`useOAuthConnect`) that UI components can call to start a flow, handle callbacks, store credentials, and expose loading / error state. | [`src/hooks/use-oauth-connect.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/hooks/use-oauth-connect.ts) |

## Core OAuth Types and Delegation

The [`src/lib/auth.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/lib/auth.ts) file establishes the provider contract through TypeScript unions and wrapper functions that delegate to the concrete adapters.

```typescript
// src/lib/auth.ts
export type OAuthProvider = 'google' | 'microsoft'
export type OAuthConfig = { clientId: string; redirectUri: string; scope: string }
export type OAuthTokens = { 
  access_token: string; 
  refresh_token?: string; 
  expires_in: number; 
  token_type: string 
}

```

The core library re-exports adapter methods through a single `providers` registry:

```typescript
export const getOAuthConfig = async (httpClient, provider) => 
  providers[provider].getOAuthConfig(httpClient)

export const buildAuthUrl = async (httpClient, provider, state, codeChallenge, redirectUri?) =>
  providers[provider].buildAuthUrl(httpClient, state, codeChallenge, redirectUri)

```

## Provider-Specific Adapters

Each OAuth provider implements four standardized functions: `getOAuthConfig`, `buildAuthUrl`, `exchangeCodeForTokens`, and `getUserInfo`.

### Google Integration

The [`src/integrations/google/auth.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/integrations/google/auth.ts) module handles Google-specific endpoints:

- **Config retrieval** – Fetches dynamic configuration from the backend endpoint `auth/google/config` and merges it with the platform-specific redirect URI determined by `getOAuthRedirectUri`.
- **Authorization URL** – Constructs `https://accounts.google.com/o/oauth2/v2/auth` with PKCE code challenge parameters.
- **Token exchange** – POSTs the authorization code to the backend endpoint `auth/google/exchange`.
- **UserInfo** – Calls the Google user-info endpoint to retrieve profile data.

### Microsoft Integration

The [`src/integrations/microsoft/auth.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/integrations/microsoft/auth.ts) file mirrors the Google structure but targets Microsoft Entra ID (formerly Azure AD) endpoints:

- **Config** – Fetches from `auth/microsoft/config` and uses Microsoft-specific client registration.
- **Authorization URL** – Points to `https://login.microsoftonline.com/.../oauth2/v2.0/authorize` with PKCE.
- **Token exchange** – POSTs to `auth/microsoft/exchange`.
- **UserInfo** – Queries the Microsoft Graph API for profile details.

Both adapters expose identical signatures, allowing the core engine to treat them interchangeably.

## Redirect Strategies and Platform Detection

The [`src/lib/oauth-redirect.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/lib/oauth-redirect.ts) module determines the appropriate callback URL based on the runtime environment:

```typescript
if (!isTauri())               // Web → same origin callback
  return window.location.origin + '/oauth/callback'

if (isMobile())               // Mobile apps – App/Universal Link
  return 'https://thunderbolt.io/oauth/callback'

return window.location.origin + '/oauth-callback.html'      // Desktop fallback

```

This logic ensures that web applications receive same-origin redirects, mobile deep links trigger the native app, and desktop clients use a local HTML file or loopback server.

## Desktop Loopback Server

For Tauri desktop environments where remote redirects are unreliable, Thunderbolt spins up a local HTTP server via the `startOAuthFlowLoopback` function in [`src/lib/oauth-loopback.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/lib/oauth-loopback.ts).

The flow proceeds as follows:

1. **Server initialization** – Invokes the Rust command `start_oauth_server` to bind to a random available port:
   ```typescript
   const port = await invoke<number>('start_oauth_server')
   const redirectUri = `http://localhost:${port}`
   ```

2. **PKCE generation** – Creates a `codeVerifier` and `codeChallenge` for the authorization request.

3. **Event registration** – Sets up a Tauri event listener for `"oauth-callback"` before opening the browser to prevent race conditions.

4. **Browser launch** – Opens the system browser with the authorization URL constructed via `buildAuthUrl`.

5. **Callback handling** – The local server receives the OAuth callback, validates the `state` parameter, and exchanges the authorization code for tokens using `exchangeCodeForTokens`.

6. **Resolution** – Returns `{ tokens, userInfo }` to the caller or `null` if the 5-minute timeout expires.

## React Integration with useOAuthConnect

The [`src/hooks/use-oauth-connect.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/hooks/use-oauth-connect.ts) hook provides the primary interface for UI components. It abstracts platform detection, state management, and credential persistence.

```typescript
const { connect, processCallback, isConnecting, error, clearError } = useOAuthConnect({
  connectingKey: 'google',
  onSuccess: () => console.log('Connected'),
})

```

The hook handles three distinct platform paths:

- **Tauri Desktop** – Invokes `startOAuthFlowLoopback`, then stores credentials via `updateSettings` on success.
- **Tauri Mobile** – Builds the auth URL, persists temporary state to SQLite (`oauth_state`, `oauth_provider`), and opens the system browser via `openUrl`. The deep-link listener later invokes `processCallback` to validate state and exchange codes.
- **Web** – Calls `redirectOAuthFlow` to navigate the browser to the provider’s consent screen. Upon return to `/oauth/callback`, the route component calls `processCallback` with the URL parameters.

The `processCallback` function (lines 59-85) validates the stored state against the callback parameter, exchanges the authorization code, saves the credentials to the settings table, clears the temporary SQLite entries, and triggers the `onSuccess` callback.

## Storing Credentials

Upon successful authentication, `saveCredentials` writes a JSON blob to the SQLite settings table:

```typescript
await updateSettings(db, {
  [`integrations_${provider}_credentials`]: JSON.stringify(credentials),
  [`integrations_${provider}_is_enabled`]: 'true',
})

```

The stored object contains the **access token**, optional **refresh token**, **expiry timestamp**, and a minimal profile including `email`, `name`, and `picture`.

## Summary

- **Thunderbolt uses a three-layer architecture**: provider adapters for Google/Microsoft, a core engine for platform abstraction, and a React hook for UI integration.
- **Provider adapters** in `src/integrations/{google,microsoft}/auth.ts` implement four standardized functions: `getOAuthConfig`, `buildAuthUrl`, `exchangeCodeForTokens`, and `getUserInfo`.
- **Platform detection** in [`src/lib/oauth-redirect.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/lib/oauth-redirect.ts) automatically selects appropriate redirect URIs for web, mobile deep links, or desktop loopback servers.
- **Desktop Tauri clients** use [`src/lib/oauth-loopback.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/lib/oauth-loopback.ts) to spawn a local HTTP server, eliminating the need for remote callback URLs.
- **The `useOAuthConnect` hook** in [`src/hooks/use-oauth-connect.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/hooks/use-oauth-connect.ts) manages the entire flow including PKCE generation, state validation, token exchange, and credential persistence.

## Frequently Asked Questions

### How does Thunderbolt handle PKCE for OAuth security?

Thunderbolt generates a PKCE code verifier and challenge within the `startOAuthFlowLoopback` function in [`src/lib/oauth-loopback.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/lib/oauth-loopback.ts). The challenge is sent to the provider's authorization endpoint, while the verifier is retained locally and sent during the token exchange. This prevents authorization code interception attacks, particularly critical for the desktop loopback server scenario where multiple applications could potentially bind to the same port.

### Can I add a new OAuth provider without modifying the core library?

Yes. To add a new provider, create a new adapter module in `src/integrations/{provider}/auth.ts` that exports the four required functions: `getOAuthConfig`, `buildAuthUrl`, `exchangeCodeForTokens`, and `getUserInfo`. Then extend the `OAuthProvider` union type in [`src/lib/auth.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/lib/auth.ts) to include your new provider string. The `useOAuthConnect` hook and redirect logic will automatically work with your new provider without additional changes.

### What is the difference between web and desktop OAuth flows in Thunderbolt?

The web flow in Thunderbolt uses `redirectOAuthFlow` to navigate the browser to the provider's consent screen, then handles the callback at `/oauth/callback` via the `processCallback` function. In contrast, the desktop Tauri flow uses `startOAuthFlowLoopback` in [`src/lib/oauth-loopback.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/lib/oauth-loopback.ts) to spawn a local HTTP server on a random port, allowing the OAuth provider to redirect to `http://localhost:{port}`. The desktop flow also uses Tauri event listeners to capture the callback without requiring a remote redirect URL.

### How are OAuth credentials stored and secured in Thunderbolt?

Upon successful authentication, `saveCredentials` in [`src/hooks/use-oauth-connect.ts`](https://github.com/thunderbird/thunderbolt/blob/main/src/hooks/use-oauth-connect.ts) stores credentials in the SQLite settings table using the `updateSettings` function. The credentials are serialized as JSON and stored under keys formatted as `integrations_${provider}_credentials` and `integrations_${provider}_is_enabled`. The actual token storage leverages the application's existing SQLite database, which on desktop platforms is encrypted by the host OS keychain or credential manager via Tauri's secure storage plugins, ensuring refresh tokens remain protected at rest.