OAuth
Sign in with Google, GitHub, and other OAuth providers.
Note: This is mock/placeholder content for demonstration purposes.
Allow users to sign in with their existing accounts from Google, GitHub, and other providers.
Supported Providers
The auth service supports many OAuth providers:
- GitHub
- GitLab
- Bitbucket
- Azure
- Discord
- Slack
- And more...
Setting Up OAuth
Configure OAuth Provider
- Configure your desired provider (e.g., Google) in your auth config
- Add your OAuth credentials:
- Client ID
- Client Secret
- Redirect URL:
https://your-app.com/auth/callback
Google OAuth Setup
- Go to Google Cloud Console
- Create a new project or select existing
- Enable Google+ API
- Create OAuth 2.0 credentials
- Add authorized redirect URIs:
- Production:
https://your-app.com/auth/callback - Development:
http://localhost:3000/auth/callback
- Production:
GitHub OAuth Setup
- Go to GitHub Settings → Developer Settings → OAuth Apps
- Click "New OAuth App"
- Fill in details:
- Application name: Your App
- Homepage URL:
https://yourapp.com - Authorization callback URL:
https://your-app.com/auth/callback
- Copy Client ID and Client Secret to your auth configuration
Implementation
OAuth Sign In Button
'use client';
import { signInWithOAuthFunction } from '../_lib/functions';
export function OAuthButtons() {
const handleGoogleSignIn = async () => {
await signInWithOAuthFunction('google');
};
const handleGitHubSignIn = async () => {
await signInWithOAuthFunction('github');
};
return (
<div className="space-y-2">
<button
onClick={handleGoogleSignIn}
className="w-full flex items-center justify-center gap-2 border rounded-lg p-2"
>
<GoogleIcon />
Continue with Google
</button>
<button
onClick={handleGitHubSignIn}
className="w-full flex items-center justify-center gap-2 border rounded-lg p-2"
>
<GitHubIcon />
Continue with GitHub
</button>
</div>
);
}
Server Function
import { createServerFn } from '@tanstack/react-start';
import * as z from 'zod';
import { errorMiddleware } from '@kit/function-middleware/server';
const OAuthProviderSchema = z.enum([
'google',
'github',
'gitlab',
'azure',
'facebook',
]);
export const signInWithOAuthFunction = createServerFn({ method: 'POST' })
.middleware([errorMiddleware])
.validator(OAuthProviderSchema)
.handler(async ({ data: provider }) => {
const origin = process.env.VITE_SITE_URL!;
const url = await signInWithOAuth({
provider,
redirectTo: `${origin}/auth/callback`,
});
// Redirect to OAuth provider
throw redirect({ href: url });
});
OAuth Callback Handler
// src/routes/auth/callback.ts
import { createFileRoute } from '@tanstack/react-router';
import { handleOAuthCallback } from '@kit/auth/server';
export const Route = createFileRoute('/auth/callback')({
server: {
handlers: {
GET: async ({ request }) => {
const requestUrl = new URL(request.url);
const code = requestUrl.searchParams.get('code');
if (code) {
await handleOAuthCallback(code);
}
// Redirect to home page
return Response.redirect(new URL('/home', request.url));
},
},
},
});
Customizing OAuth Flow
Scopes
Request specific permissions:
await signInWithOAuth({
provider: 'google',
scopes: ['email', 'profile', 'https://www.googleapis.com/auth/calendar'],
});
Query Parameters
Pass custom parameters:
await signInWithOAuth({
provider: 'azure',
queryParams: {
prompt: 'consent',
access_type: 'offline',
},
});
Skip Browser Redirect
For mobile apps or custom flows:
const url = await signInWithOAuth({
provider: 'google',
skipRedirect: true,
});
// url contains the OAuth URL
// Handle redirect manually
Account Linking
Linking Additional Providers
Allow users to link multiple OAuth accounts:
export const linkOAuthProviderFunction = createServerFn({ method: 'POST' })
.middleware([errorMiddleware, authMiddleware])
.validator(OAuthProviderSchema)
.handler(async ({ data: provider }) => {
const user = await requireAuth();
const url = await linkOAuthProvider({
userId: user.id,
provider,
});
throw redirect({ href: url });
});
Unlinking Providers
export const unlinkOAuthProviderFunction = createServerFn({ method: 'POST' })
.middleware([errorMiddleware, authMiddleware])
.validator(
z.object({
provider: z.string(),
identityId: z.string(),
}),
)
.handler(async ({ data }) => {
await unlinkOAuthProvider({
identityId: data.identityId,
});
// The client re-fetches the linked identities via router.invalidate()
});
Viewing Linked Identities
import { getSession } from '@kit/auth/server';
export async function getLinkedIdentities() {
const session = await getSession();
return session?.user.identities || [];
}
User Data from OAuth
Accessing Provider Data
import { getSession } from '@kit/auth/server';
const session = await getSession();
const user = session?.user;
// User metadata from provider
const {
name,
avatarUrl,
email,
} = user;
// Provider-specific data
const identities = user.identities || [];
const googleIdentity = identities.find(i => i.provider === 'google');
console.log(googleIdentity?.data);
Storing Additional Data
export const completeOAuthProfileFunction = createServerFn({ method: 'POST' })
.middleware([errorMiddleware, authMiddleware])
.validator(ProfileSchema)
.handler(async ({ data }) => {
const user = await requireAuth();
// Update user profile
await updateUserProfile({
userId: user.id,
username: data.username,
bio: data.bio,
avatarUrl: user.avatarUrl,
});
throw redirect({ href: '/home' });
});
Configuration
Enable OAuth in Config
// config/auth.config.ts
export const authConfig = {
providers: {
emailPassword: true,
oAuth: ['google', 'github'],
},
};
Conditional Rendering
import { authConfig } from '~/config/auth.config';
export function AuthProviders() {
return (
<>
{authConfig.providers.emailPassword && <EmailPasswordForm />}
{authConfig.providers.oAuth?.includes('google') && (
<GoogleSignInButton />
)}
{authConfig.providers.oAuth?.includes('github') && (
<GitHubSignInButton />
)}
</>
);
}
Troubleshooting
Redirect URI Mismatch
Ensure redirect URIs match exactly:
- Check auth configuration
- Verify OAuth app settings in provider console
- Use exact URLs (including http/https)
Missing Email
Some providers don't share email by default:
import { getSession } from '@kit/auth/server';
const session = await getSession();
if (!session?.user.email) {
// Request email separately or prompt user
redirect('/auth/complete-profile');
}
Rate Limiting
OAuth providers may rate limit requests:
- Cache OAuth tokens appropriately
- Don't make excessive authorization requests
- Handle rate limit errors gracefully
Best Practices
- Request minimum scopes - Only ask for what you need
- Handle errors gracefully - OAuth can fail for many reasons
- Verify email addresses - Some providers don't verify emails
- Support account linking - Let users connect multiple providers
- Provide fallback - Always offer email/password as backup
- Log OAuth events - Track sign-ins and linking attempts
- Test thoroughly - Test with real provider accounts