Sigma Auth
Customization

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:

bitcoin-oauth.js
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:

google-oauth.js
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:

github-oauth.js
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

  1. User authenticates with Bitcoin provider first
  2. Bitcoin public key becomes the canonical identity
  3. Additional providers are linked to the Bitcoin identity
  4. Future logins with any provider resolve to the same user

Implementation

account-linking.js
// 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-provider.js
// 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

oauth-restore.js
// 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:

  1. OAuth credentials (Google, GitHub login)
  2. Backup password (set during initial backup)
passwordless-restore.js
// 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:

.env
# 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 Connect
  • profile - User profile information
  • email - Email address

GitHub Scopes:

  • user:email - Email addresses
  • read:user - User profile
  • repo - Repository access (if needed)

Multi-Provider Authentication

Provider Selection UI

ProviderSelector.tsx
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

hooks/useUniversalAuth.ts
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

provider-error-handler.js
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

retry-logic.js
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:

provider-migration.js
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:

data-export.js
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

  1. Always verify provider responses server-side
  2. Use HTTPS for all OAuth redirects
  3. Validate state parameters to prevent CSRF
  4. Store tokens securely (encrypted or httpOnly cookies)
  5. Implement token refresh for long-lived sessions

User Experience

  1. Clear provider selection with recognizable icons
  2. Explain account linking before proceeding
  3. Show linked accounts in user profile
  4. Allow account unlinking with proper warnings
  5. Graceful fallbacks when providers are unavailable

Performance

  1. Cache provider configurations to reduce API calls
  2. Parallel token validation for multiple providers
  3. Background profile updates for linked accounts
  4. Efficient session management across providers
  5. CDN for provider assets (icons, scripts)