OAuthProviders
OAuth provider selection component for linking cloud backup storage
OAuthProviders
A component for displaying and managing OAuth provider connections for cloud backup storage. Supports multiple providers with official brand colors and flexible configuration.
OAuthProviders Demo
OAuth provider selection component for linking cloud backup storage with multiple providers.
Configuration
Linked Providers
Recent Events
Default Providers
Custom Providers
Note: Dropbox is disabled in this example
Different Actions
Try:
- Change action context to see different button labels
- Click providers to link/unlink them
- Try different sizes and disabled state
- Notice linked providers show checkmarks
- Watch events update in real-time
Installation
npx bigblocks add oauth-providers
Import
import { OAuthProviders } from 'bigblocks';
Props
Prop | Type | Required | Default | Description |
---|---|---|---|---|
providers | OAuthProvider[] | No | Default providers | Custom provider configuration |
action | 'signin' | 'signup' | 'link' | No | 'link' | Action context |
callbackUrl | string | No | - | OAuth callback URL |
linkedProviders | string[] | No | [] | Already linked provider IDs |
onProviderClick | (provider: string) => void | No | - | Provider click handler |
disabled | boolean | No | false | Disable all providers |
loading | boolean | No | false | Loading state |
className | string | No | - | Additional CSS classes |
size | '1' | '2' | '3' | No | '2' | Button size |
Types
interface OAuthProvider {
id: string;
name: string;
icon: React.ReactNode;
enabled?: boolean;
}
Basic Usage
import { OAuthProviders } from 'bigblocks';
export default function BackupSettings() {
const handleProviderClick = (provider: string) => {
console.log('Selected provider:', provider);
// Initiate OAuth flow
window.location.href = `/api/auth/link?provider=${provider}`;
};
return (
<OAuthProviders
onProviderClick={handleProviderClick}
linkedProviders={['google']}
/>
);
}
Advanced Usage
With Custom Providers
import { OAuthProviders } from 'bigblocks';
const customProviders = [
{
id: 'google',
name: 'Google',
icon: <GoogleIcon />,
enabled: true,
},
{
id: 'github',
name: 'GitHub',
icon: <GitHubIcon />,
enabled: true,
},
{
id: 'microsoft',
name: 'Microsoft',
icon: <MicrosoftIcon />,
enabled: false, // Disabled
},
];
export default function CustomProviders() {
return (
<OAuthProviders
providers={customProviders}
onProviderClick={(provider) => {
console.log('Clicked:', provider);
}}
/>
);
}
With Linked Status
import { OAuthProviders } from 'bigblocks';
import { useConnectedAccounts } from '@/hooks/useConnectedAccounts';
export default function LinkedProviders() {
const { data: accounts } = useConnectedAccounts();
const linkedProviders = accounts?.map(a => a.provider) || [];
return (
<OAuthProviders
linkedProviders={linkedProviders}
onProviderClick={(provider) => {
if (linkedProviders.includes(provider)) {
// Already linked - maybe unlink?
console.log('Already linked:', provider);
} else {
// Link new provider
window.location.href = `/api/auth/link?provider=${provider}`;
}
}}
/>
);
}
Different Actions
import { OAuthProviders } from 'bigblocks';
export default function ActionExamples() {
return (
<div className="space-y-4">
{/* Sign in with OAuth */}
<OAuthProviders
action="signin"
onProviderClick={(provider) => {
window.location.href = `/api/auth/signin?provider=${provider}`;
}}
/>
{/* Sign up with OAuth */}
<OAuthProviders
action="signup"
onProviderClick={(provider) => {
window.location.href = `/api/auth/signup?provider=${provider}`;
}}
/>
{/* Link for backup */}
<OAuthProviders
action="link"
onProviderClick={(provider) => {
window.location.href = `/api/auth/link?provider=${provider}`;
}}
/>
</div>
);
}
With Loading State
import { OAuthProviders } from 'bigblocks';
import { useState } from 'react';
export default function LoadingExample() {
const [isLoading, setIsLoading] = useState(false);
const handleProviderClick = async (provider: string) => {
setIsLoading(true);
try {
await linkProvider(provider);
} finally {
setIsLoading(false);
}
};
return (
<OAuthProviders
onProviderClick={handleProviderClick}
loading={isLoading}
disabled={isLoading}
/>
);
}
Custom Sizing
import { OAuthProviders } from 'bigblocks';
export default function SizingExample() {
return (
<div className="space-y-4">
<OAuthProviders size="1" onProviderClick={console.log} />
<OAuthProviders size="2" onProviderClick={console.log} />
<OAuthProviders size="3" onProviderClick={console.log} />
</div>
);
}
Brand Colors
The component exports official brand colors for OAuth providers:
import { OAUTH_BRAND_COLORS } from 'bigblocks';
// Access brand colors
const googleBlue = OAUTH_BRAND_COLORS.google.blue; // #4285F4
const githubDark = OAUTH_BRAND_COLORS.github; // #24292e
const twitterBlue = OAUTH_BRAND_COLORS.twitter; // #1DA1F2
const handcashGreen = OAUTH_BRAND_COLORS.handcash; // #38CB7C
const discordPurple = OAUTH_BRAND_COLORS.discord; // #5865F2
const facebookBlue = OAUTH_BRAND_COLORS.facebook; // #1877F2
const microsoftBlue = OAUTH_BRAND_COLORS.microsoft; // #00BCF2
Common Patterns
In Settings Page
import { OAuthProviders } from 'bigblocks';
export function SecuritySettings() {
const { data: user } = useAuth();
const linkedProviders = user?.connectedAccounts || [];
return (
<div className="space-y-4">
<div>
<h3 className="text-lg font-semibold">Cloud Backup Providers</h3>
<p className="text-sm text-gray-600">
Link providers to backup your wallet
</p>
</div>
<OAuthProviders
linkedProviders={linkedProviders}
onProviderClick={(provider) => {
if (linkedProviders.includes(provider)) {
if (confirm(`Unlink ${provider}?`)) {
unlinkProvider(provider);
}
} else {
linkProvider(provider);
}
}}
/>
<div className="text-sm text-gray-500">
{linkedProviders.length === 0 && (
<p>No providers linked yet</p>
)}
{linkedProviders.length > 0 && (
<p>Linked: {linkedProviders.join(', ')}</p>
)}
</div>
</div>
);
}
In Signup Flow
import { OAuthProviders } from 'bigblocks';
export function SignupStep() {
const [step, setStep] = useState('create');
return (
<div>
{step === 'create' && (
<div>
<h2>Create Your Account</h2>
<CreateIdentityForm onComplete={() => setStep('backup')} />
</div>
)}
{step === 'backup' && (
<div>
<h2>Backup Your Wallet</h2>
<p>Link a cloud provider for automatic backups</p>
<OAuthProviders
action="link"
onProviderClick={(provider) => {
// Store provider choice
sessionStorage.setItem('backupProvider', provider);
// Redirect to OAuth
window.location.href = `/api/auth/link?provider=${provider}`;
}}
/>
<button onClick={() => setStep('complete')}>
Skip for now
</button>
</div>
)}
</div>
);
}
With Custom Styling
import { OAuthProviders } from 'bigblocks';
export function StyledProviders() {
return (
<div className="bg-gray-50 p-6 rounded-lg">
<OAuthProviders
className="gap-4"
onProviderClick={(provider) => {
console.log('Selected:', provider);
}}
/>
</div>
);
}
Provider Setup
Each provider requires OAuth app configuration:
- Visit Google Cloud Console
- Create OAuth 2.0 credentials
- Add redirect URI:
https://yourdomain.com/api/auth/callback/google
- Enable Google Drive API for backup storage
GitHub
- Visit GitHub Developer Settings
- Create OAuth App
- Add redirect URI:
https://yourdomain.com/api/auth/callback/github
- Request
gist
scope for backup storage
- Visit Twitter Developer Portal
- Create OAuth 2.0 app
- Add redirect URI:
https://yourdomain.com/api/auth/callback/twitter
HandCash
- Visit HandCash Developer Portal
- Create app
- Add redirect URI:
https://yourdomain.com/api/auth/callback/handcash
Styling
The component uses Radix Themes buttons and can be customized:
/* Custom provider button styles */
.oauth-providers {
display: flex;
gap: 1rem;
flex-wrap: wrap;
}
.oauth-provider-button {
min-width: 120px;
}
.oauth-provider-button[data-linked="true"] {
opacity: 0.7;
position: relative;
}
.oauth-provider-button[data-linked="true"]::after {
content: "✓";
position: absolute;
top: 0;
right: 0;
background: green;
color: white;
border-radius: 50%;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
}
Best Practices
- Clear Action Context: Use appropriate
action
prop for context - Loading States: Show loading feedback during OAuth flows
- Error Handling: Handle OAuth failures gracefully
- Security: Always validate OAuth responses server-side
- Accessibility: Ensure keyboard navigation works
Troubleshooting
Providers Not Showing
- Check that providers array is properly configured
- Ensure
enabled
is true for each provider - Verify component is wrapped in theme provider
Click Handler Not Working
- Ensure
onProviderClick
is properly defined - Check for event propagation issues
- Verify buttons aren't disabled
OAuth Flow Issues
- Verify redirect URIs match exactly
- Check OAuth app permissions/scopes
- Ensure callback handlers are implemented
Related Components
- SignupFlow - Uses during registration
- LoginForm - OAuth sign-in option
- CloudBackupManager - Manages backups
- OAuthRestoreFlow - Restore from OAuth
API Reference
Default Providers
The component includes these providers by default:
- Google (id: 'google')
- GitHub (id: 'github')
- Twitter (id: 'twitter')
- HandCash (id: 'handcash')
Each can be customized or filtered using the providers
prop.
Notes for Improvement
Enhanced Implementation: The actual component is more sophisticated than the prompt suggested:
- Supports custom provider configurations
- Includes brand color constants
- Has size variants for different contexts
- More flexible action contexts (signin/signup/link)
- Better TypeScript support with proper interfaces