Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/stack-auth/stack-auth/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Stack Auth supports OAuth connections for authentication and connected accounts. Users can sign in with OAuth providers or connect additional OAuth accounts to their profile.

Connected Accounts

Connected accounts allow users to link multiple OAuth providers to a single Stack Auth account without using them for authentication.

Account Structure

{
  user_id: string,
  provider: string,  // Provider config ID
  provider_account_id: string,  // Unique ID from OAuth provider
}

OAuth Sign-In Flow

Finding Existing Accounts

When a user signs in with OAuth:
import { findExistingOAuthAccount } from '@/lib/oauth';

const account = await findExistingOAuthAccount(
  prisma,
  tenancyId,
  providerId,
  providerAccountId
);

if (account) {
  // User exists, sign them in
  const userId = getProjectUserIdFromOAuthAccount(account);
}

Account Merge Strategies

When a new OAuth sign-in has the same email as an existing user, Stack Auth supports three strategies: Automatically links the OAuth account to the existing user if both emails are verified:
config: {
  auth: {
    oauth: {
      accountMergeStrategy: 'link_method'
    }
  }
}
Behavior:
  • If existing email is verified AND OAuth email is verified → Link accounts
  • Otherwise → Throw error

2. Raise Error

Always prevents duplicate accounts by throwing an error:
config: {
  auth: {
    oauth: {
      accountMergeStrategy: 'raise_error'
    }
  }
}

3. Allow Duplicates

Creates separate accounts but disables email authentication:
config: {
  auth: {
    oauth: {
      accountMergeStrategy: 'allow_duplicates'
    }
  }
}

Creating OAuth Connections

New User with OAuth

import { createOAuthUserAndAccount } from '@/lib/oauth';

const { projectUserId, oauthAccountId } = await createOAuthUserAndAccount(
  prisma,
  tenancy,
  {
    providerId: 'google',
    providerAccountId: 'google-user-123',
    email: 'user@example.com',
    emailVerified: true,
    primaryEmailAuthEnabled: true,
    displayName: 'John Doe',
    profileImageUrl: 'https://...',
    signUpRuleOptions: { /* ... */ },
  }
);
import { linkOAuthAccountToUser } from '@/lib/oauth';

const { oauthAccountId } = await linkOAuthAccountToUser(
  prisma,
  {
    tenancyId,
    providerId: 'github',
    providerAccountId: 'github-user-456',
    email: 'user@example.com',
    projectUserId: 'existing-user-id',
  }
);

Access Tokens

Retrieve OAuth access tokens for connected accounts:
import { stackServerApp } from '@/stack';

const user = await stackServerApp.getUser();
const connectedAccounts = await user.listConnectedAccounts();

for (const account of connectedAccounts) {
  // Get fresh access token
  const token = await account.getAccessToken({
    scope: 'read:user',  // Optional: request specific scopes
  });
  
  console.log('Access token:', token.access_token);
}

Managing Connected Accounts

List Connected Accounts

const accounts = await stackServerApp.listConnectedAccounts(userId);

accounts.forEach(account => {
  console.log(`Provider: ${account.provider}`);
  console.log(`Account ID: ${account.provider_account_id}`);
});

Get Specific Connected Account

const account = await stackServerApp.getConnectedAccount(
  userId,
  'google',
  'google-account-id'
);

Disconnect Account

await stackServerApp.deleteConnectedAccount(
  userId,
  'google',
  'google-account-id'
);

OAuth Configuration

Configure OAuth providers in your Stack Auth project:
config: {
  auth: {
    oauth: {
      accountMergeStrategy: 'link_method',
      providers: [
        {
          id: 'google',
          enabled: true,
          clientId: process.env.GOOGLE_CLIENT_ID,
          clientSecret: process.env.GOOGLE_CLIENT_SECRET,
        },
        {
          id: 'github',
          enabled: true,
          clientId: process.env.GITHUB_CLIENT_ID,
          clientSecret: process.env.GITHUB_CLIENT_SECRET,
        },
      ],
    },
  },
}

Best Practices

  • Always verify email addresses when linking accounts
  • Store minimal OAuth data - only what you need
  • Refresh access tokens before they expire
  • Handle OAuth errors gracefully - providers may be temporarily unavailable
  • Use account merge strategy carefully - choose based on your security requirements
  • Test with multiple providers to ensure consistent behavior

Common Use Cases

Social Login

Allow users to sign in with their favorite social media accounts:
// User clicks "Sign in with Google"
await stackServerApp.signInWithOAuth('google');

API Integration

Access third-party APIs on behalf of users:
const account = await user.getConnectedAccount('github');
const token = await account.getAccessToken();

// Use token to call GitHub API
const response = await fetch('https://api.github.com/user/repos', {
  headers: { Authorization: `Bearer ${token.access_token}` },
});

Profile Enrichment

Enhance user profiles with data from OAuth providers:
const googleAccount = await user.getConnectedAccount('google');
const token = await googleAccount.getAccessToken();

// Fetch Google profile data
const profile = await fetch('https://www.googleapis.com/oauth2/v1/userinfo', {
  headers: { Authorization: `Bearer ${token.access_token}` },
});

Build docs developers (and LLMs) love