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:
1. Link Method (Default)
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: { /* ... */ },
}
);
Link OAuth to Existing User
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}` },
});