Sigma Auth supports multiple authentication providers through its unified OAuth 2.0 interface. Users can link multiple providers to a single Bitcoin identity.
Supported Providers
Sigma Provider (Primary)
The main authentication method using Bitcoin cryptographic signatures:
const authUrl = new URL('/login', 'https://auth.sigmaidentity.com');
authUrl.searchParams.set('provider', 'sigma');
authUrl.searchParams.set('client_id', 'your-app');
authUrl.searchParams.set('redirect_uri', 'https://yourapp.com/callback');
authUrl.searchParams.set('response_type', 'code');
Google OAuth
Standard Google OAuth 2.0 integration:
const authUrl = new URL('/login', 'https://auth.sigmaidentity.com');
authUrl.searchParams.set('provider', 'google');
authUrl.searchParams.set('client_id', 'your-app');
authUrl.searchParams.set('redirect_uri', 'https://yourapp.com/callback');
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('scope', 'openid profile email');
GitHub OAuth
GitHub authentication with repository access:
const authUrl = new URL('/authorize', 'https://auth.sigmaidentity.com');
authUrl.searchParams.set('provider', 'github');
authUrl.searchParams.set('client_id', 'your-app');
authUrl.searchParams.set('redirect_uri', 'https://yourapp.com/callback');
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('scope', 'user:email');
Account Linking
Multiple OAuth providers can be linked to a single Bitcoin identity. This allows users to authenticate using any linked method while maintaining a consistent identity.
Linking Flow
- User authenticates with Bitcoin provider first
- Bitcoin public key becomes the canonical identity
- Additional providers are linked to the Bitcoin identity
- Future logins with any provider resolve to the same user
Implementation
// Check if account should be linked
const linkAccount = async (bitcoinAddress, oauthProvider, oauthId) => {
// Check if Bitcoin identity already exists
const existingUser = await getUserByBitcoinAddress(bitcoinAddress);
if (existingUser) {
// Link the OAuth account
await linkOAuthProvider(existingUser.id, {
provider: oauthProvider,
providerId: oauthId,
linkedAt: new Date()
});
return existingUser;
} else {
// Create new user with linked account
return await createUser({
bitcoinAddress,
linkedAccounts: [{
provider: oauthProvider,
providerId: oauthId,
linkedAt: new Date()
}]
});
}
};
Account Linking API
// Link additional provider to existing Bitcoin identity
const linkProvider = async (accessToken, provider) => {
const response = await fetch('https://auth.sigmaidentity.com/link', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
provider: provider,
redirect_uri: 'https://yourapp.com/link-callback'
})
});
const { authorization_url } = await response.json();
window.location.href = authorization_url;
};
Backup Restoration
OAuth providers enable seamless cross-device wallet restoration without requiring the original Bitcoin private key.
Cross-Device Restore Flow
// Restore wallet from linked OAuth account
const restoreFromOAuth = async (provider) => {
try {
// Step 1: Redirect to OAuth restore page
const restoreUrl = `https://auth.sigmaidentity.com/oauth-restore?provider=${provider}`;
window.location.href = restoreUrl;
// Step 2: Handle OAuth callback (implemented in callback page)
const handleOAuthCallback = async (oauthId, accountId) => {
// Fetch encrypted backup using OAuth credentials
const response = await fetch(`/backup/oauth?oauthId=${oauthId}`);
const backupData = await response.json();
if (backupData.error) {
throw new Error('No backup found for this OAuth account');
}
// Decrypt backup with user's password
const password = await promptForPassword();
const decryptedBackup = await decryptBackup(backupData.data, password);
// Restore Bitcoin identity
await restoreFromBackup(decryptedBackup);
console.log('Wallet restored successfully!');
};
} catch (error) {
console.error('Restore failed:', error);
}
};
Restore Without Bitcoin Key
Users can restore their wallet using only:
- OAuth credentials (Google, GitHub login)
- Backup password (set during initial backup)
// Complete restoration flow for new device
const restoreOnNewDevice = async () => {
// User selects provider (Google or GitHub)
const provider = await selectProvider();
// OAuth authentication
const oauthResult = await authenticateWithProvider(provider);
// Fetch encrypted backup
const backup = await fetchBackupByOAuthId(oauthResult.oauthId);
// Decrypt with password
const password = await promptSecurePassword();
const wallet = await decryptWallet(backup.data, password);
// User is now authenticated with their Bitcoin identity
return wallet;
};
Security Features
- Client-side decryption: Passwords never leave the user's device
- Automatic linking: OAuth accounts are linked during initial authentication
- Encrypted storage: Backups are encrypted before storage
- No private key exposure: OAuth restore doesn't require the original Bitcoin key
Provider Configuration
Environment Variables
Configure OAuth providers with environment variables:
# Google OAuth
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
# GitHub OAuth
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
# Bitcoin provider (always enabled)
BITCOIN_NETWORK=mainnet
Provider-Specific Scopes
Each provider supports different scopes:
Google Scopes:
openid
- Basic OpenID Connectprofile
- User profile informationemail
- Email address
GitHub Scopes:
user:email
- Email addressesread:user
- User profilerepo
- Repository access (if needed)
Multi-Provider Authentication
Provider Selection UI
interface AuthProvider {
id: string;
name: string;
icon: string;
primary?: boolean;
}
const providers: AuthProvider[] = [
{ id: 'bitcoin', name: 'Bitcoin', icon: '₿', primary: true },
{ id: 'google', name: 'Google', icon: '🔗' },
{ id: 'github', name: 'GitHub', icon: '🔗' }
];
function ProviderSelector({ onSelect }: { onSelect: (provider: string) => void }) {
return (
<div className="provider-grid">
{providers.map(provider => (
<button
key={provider.id}
onClick={() => onSelect(provider.id)}
className={`provider-button ${provider.primary ? 'primary' : ''}`}
>
<span className="provider-icon">{provider.icon}</span>
<span className="provider-name">{provider.name}</span>
</button>
))}
</div>
);
}
Universal Authentication Hook
interface AuthOptions {
provider: 'bitcoin' | 'google' | 'github';
redirectUri: string;
state?: string;
}
export function useUniversalAuth() {
const authenticate = useCallback(async (options: AuthOptions) => {
const authUrl = new URL('/authorize', 'https://auth.sigmaidentity.com');
// Common parameters
authUrl.searchParams.set('client_id', process.env.NEXT_PUBLIC_CLIENT_ID!);
authUrl.searchParams.set('redirect_uri', options.redirectUri);
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('provider', options.provider);
if (options.state) {
authUrl.searchParams.set('state', options.state);
}
// Provider-specific parameters
switch (options.provider) {
case 'google':
authUrl.searchParams.set('scope', 'openid profile email');
break;
case 'github':
authUrl.searchParams.set('scope', 'user:email');
break;
case 'bitcoin':
// No additional scopes needed
break;
}
window.location.href = authUrl.toString();
}, []);
return { authenticate };
}
Provider-Specific Features
Google Integration
Profile Information:
- Full name
- Email address (verified)
- Profile picture
- Google ID
Additional Features:
- Google Calendar integration
- Gmail API access (with additional scopes)
- Google Drive integration
GitHub Integration
Profile Information:
- GitHub username
- Email addresses
- Avatar URL
- GitHub ID
Additional Features:
- Repository access
- Organization membership
- Commit history
- Issue and PR management
Bitcoin Provider Features
Identity Information:
- Bitcoin address
- Public key
- BAP profile (if available)
- On-chain attestations
Additional Features:
- Cryptographic proof of identity
- Zero server secrets
- Decentralized identity
- Blockchain-based verification
Error Handling
Provider-Specific Errors
const handleProviderError = (error, provider) => {
switch (provider) {
case 'google':
if (error.error === 'access_denied') {
return 'Google authentication was cancelled';
}
break;
case 'github':
if (error.error === 'application_suspended') {
return 'GitHub application is suspended';
}
break;
case 'bitcoin':
if (error.error === 'signature_invalid') {
return 'Bitcoin signature verification failed';
}
break;
}
return `Authentication failed: ${error.error_description || error.error}`;
};
Retry Logic
const authenticateWithRetry = async (provider, maxRetries = 3) => {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await authenticate(provider);
} catch (error) {
if (attempt === maxRetries) {
throw error;
}
// Wait before retry (exponential backoff)
await new Promise(resolve =>
setTimeout(resolve, Math.pow(2, attempt) * 1000)
);
}
}
};
Provider Migration
Migrating Between Providers
Users can migrate from one primary provider to another:
const migrateProvider = async (fromProvider, toProvider, userId) => {
// 1. Verify user controls both accounts
const verification = await verifyBothProviders(userId, fromProvider, toProvider);
if (!verification.valid) {
throw new Error('Cannot verify ownership of both accounts');
}
// 2. Update primary provider
await updateUserPrimaryProvider(userId, toProvider);
// 3. Maintain linked accounts
await maintainLinkedAccounts(userId);
return { success: true, newPrimaryProvider: toProvider };
};
Data Portability
Export user data for migration:
const exportUserData = async (userId) => {
const user = await getUserById(userId);
return {
identity: {
bitcoinAddress: user.bitcoinAddress,
publicKey: user.publicKey
},
linkedAccounts: user.linkedAccounts.map(account => ({
provider: account.provider,
providerId: account.providerId,
linkedAt: account.linkedAt
})),
profile: user.profile,
attestations: user.attestations,
exportedAt: new Date().toISOString()
};
};
Best Practices
Security
- Always verify provider responses server-side
- Use HTTPS for all OAuth redirects
- Validate state parameters to prevent CSRF
- Store tokens securely (encrypted or httpOnly cookies)
- Implement token refresh for long-lived sessions
User Experience
- Clear provider selection with recognizable icons
- Explain account linking before proceeding
- Show linked accounts in user profile
- Allow account unlinking with proper warnings
- Graceful fallbacks when providers are unavailable
Performance
- Cache provider configurations to reduce API calls
- Parallel token validation for multiple providers
- Background profile updates for linked accounts
- Efficient session management across providers
- CDN for provider assets (icons, scripts)