Skip to content

Authentication

Learn how authentication works in Civra and how to add it to your Web3 applications.

Civra Platform Authentication

Sign Up Methods

Google OAuth

  • One-click signup with Google account
  • Automatic profile creation
  • Free plan with 10 message credits

GitHub OAuth

  • Perfect for developers
  • Connect GitHub repos (coming soon)
  • Same free tier benefits

How It Works

1. Click "Sign In"

2. Choose provider (Google/GitHub)

3. Authorize Civra

4. Auto-create:
   - User profile
   - Free subscription
   - Initial credits (10 msg, 100 int)

5. Start building!

Security Features

Supabase Auth

  • Industry-standard authentication
  • JWT-based sessions
  • Secure cookie storage
  • Automatic token refresh

Row Level Security (RLS)

sql
-- Users can only access their own data
CREATE POLICY "Users can view own projects"
  ON projects FOR SELECT
  USING (auth.uid() = user_id);

Server-Side Validation

typescript
// All API routes validate auth
export async function POST(req: Request) {
  const session = await getServerSession(authOptions)
  if (!session) {
    return new Response('Unauthorized', { status: 401 })
  }
  // ... protected logic
}

Adding Auth to Your dApp

Web3 Wallet Authentication

Civra makes it easy to add wallet-based auth to your applications.

Basic Setup

typescript
import { WalletAuth } from '@civra/web3'

export default function App() {
  return (
    <WalletAuth>
      <YourApp />
    </WalletAuth>
  )
}

Connect Wallet

typescript
import { useWalletAuth } from '@civra/web3'

export function ConnectButton() {
  const { connect, disconnect, address, isConnected } = useWalletAuth()

  if (isConnected) {
    return (
      <div>
        <span>{address}</span>
        <button onClick={disconnect}>Disconnect</button>
      </div>
    )
  }

  return <button onClick={connect}>Connect Wallet</button>
}

Sign-In With Ethereum (SIWE)

Prove wallet ownership:

typescript
import { useSignIn } from '@civra/web3'

export function SignInButton() {
  const { signIn, isLoading } = useSignIn()

  const handleSignIn = async () => {
    try {
      const message = `Sign in to MyApp\n\nNonce: ${Date.now()}`
      const signature = await signIn(message)

      // Verify signature on backend
      const response = await fetch('/api/auth/verify', {
        method: 'POST',
        body: JSON.stringify({ message, signature })
      })

      if (response.ok) {
        console.log('Signed in!')
      }
    } catch (error) {
      console.error('Sign in failed:', error)
    }
  }

  return (
    <button onClick={handleSignIn} disabled={isLoading}>
      {isLoading ? 'Signing...' : 'Sign In'}
    </button>
  )
}

Backend Verification

typescript
// app/api/auth/verify/route.ts
import { verifyMessage } from 'ethers'

export async function POST(req: Request) {
  const { message, signature } = await req.json()

  // Verify signature
  const address = verifyMessage(message, signature)

  // Create session
  const session = await createSession(address)

  return Response.json({ success: true, session })
}

Authentication Patterns

1. Wallet-Only Auth

Simplest approach - no email/password needed.

typescript
// Just connect wallet
const { address } = useWallet()

// Use address as user ID
const userProfile = await fetchProfile(address)

Pros:

  • ✅ Truly decentralized
  • ✅ No passwords to manage
  • ✅ Privacy-preserving

Cons:

  • ❌ Lose wallet = lose access
  • ❌ No account recovery
  • ❌ One device at a time

Best for: Pure dApps, DeFi, NFT platforms

2. Hybrid Auth (Wallet + Email)

Combine wallet and traditional auth.

typescript
import { useHybridAuth } from '@civra/web3'

export function AuthComponent() {
  const {
    signInWithEmail,
    signInWithWallet,
    linkWallet,
    user
  } = useHybridAuth()

  // User can sign in via email first
  await signInWithEmail('user@example.com')

  // Then link their wallet
  await linkWallet()
}

Pros:

  • ✅ Account recovery via email
  • ✅ Multi-device support
  • ✅ Fallback option

Cons:

  • ❌ Less decentralized
  • ❌ Email required
  • ❌ More complex

Best for: Web3 games, social dApps, marketplaces

3. NFT-Gated Auth

Require NFT ownership for access.

typescript
import { useNFTGate } from '@civra/web3'

export function ProtectedContent() {
  const { hasNFT, loading } = useNFTGate({
    contract: '0x...',
    chainId: 1
  })

  if (loading) return <div>Checking NFT...</div>
  if (!hasNFT) return <div>You need the NFT to access this</div>

  return <div>Welcome, NFT holder!</div>
}

Use Cases:

  • Exclusive communities
  • Premium content
  • Member-only features
  • Governance participation

4. Token-Gated Auth

Require token balance for access.

typescript
import { useTokenGate } from '@civra/web3'

export function VIPSection() {
  const { hasBalance, balance } = useTokenGate({
    token: '0x...',
    minAmount: '1000', // 1000 tokens minimum
    chainId: 137
  })

  if (!hasBalance) {
    return (
      <div>
        You need 1,000 tokens to access.
        Current balance: {balance}
      </div>
    )
  }

  return <div>Welcome, VIP member!</div>
}

Use Cases:

  • Tiered access
  • Governance voting
  • Staking rewards
  • Premium features

5. Multi-Sig Auth

Require multiple signatures.

typescript
import { useMultiSig } from '@civra/web3'

export function AdminPanel() {
  const { requestSignatures, approvals } = useMultiSig({
    required: 3,
    signers: ['0x...', '0x...', '0x...']
  })

  const executeAction = async () => {
    const signatures = await requestSignatures({
      message: 'Approve admin action',
      action: 'transfer_funds'
    })

    if (signatures.length >= 3) {
      // Execute action
    }
  }
}

Use Cases:

  • Treasury management
  • Admin actions
  • High-value transactions
  • DAO operations

Session Management

Persistent Sessions

Keep users logged in:

typescript
// Auto-reconnect on page load
const { autoConnect } = useWalletAuth()

useEffect(() => {
  autoConnect()
}, [])

Session Timeout

Add security with timeouts:

typescript
const SESSION_TIMEOUT = 30 * 60 * 1000 // 30 minutes

const { lastActivity, resetTimer } = useSession()

useEffect(() => {
  const timeout = setTimeout(() => {
    if (Date.now() - lastActivity > SESSION_TIMEOUT) {
      disconnect()
    }
  }, SESSION_TIMEOUT)

  return () => clearTimeout(timeout)
}, [lastActivity])

Multi-Chain Sessions

Support multiple networks:

typescript
const { sessions } = useMultiChainAuth()

// Separate session per chain
const ethereumSession = sessions[1]
const polygonSession = sessions[137]

Security Best Practices

1. Verify Signatures Server-Side

typescript
// ❌ Don't trust client
if (clientSignature === expectedSignature) { ... }

// ✅ Verify on server
const recoveredAddress = verifyMessage(message, signature)
if (recoveredAddress === expectedAddress) { ... }

2. Use Nonces

Prevent replay attacks:

typescript
// Generate unique nonce
const nonce = crypto.randomUUID()

// Store nonce
await redis.set(`nonce:${nonce}`, true, 'EX', 300)

// Verify nonce hasn't been used
const message = `Sign in\nNonce: ${nonce}`

3. Check Chain ID

Prevent cross-chain attacks:

typescript
const { chainId } = useNetwork()

if (chainId !== 1) {
  throw new Error('Please switch to Ethereum Mainnet')
}

4. Implement Rate Limiting

typescript
// Limit sign-in attempts
const attempts = await redis.incr(`attempts:${address}`)

if (attempts > 5) {
  throw new Error('Too many attempts. Try again later.')
}

5. Sanitize Inputs

typescript
import { isAddress } from 'ethers'

if (!isAddress(userInput)) {
  throw new Error('Invalid address')
}

OAuth Integration

Add Social Login

typescript
import { signIn } from 'next-auth/react'

// Google
await signIn('google')

// GitHub
await signIn('github')

// Discord
await signIn('discord')

// Twitter
await signIn('twitter')
typescript
// Link wallet to social account
await linkAccount({
  provider: 'google',
  wallet: address
})

// Sign in with either
const user = await signIn('google')
// or
const user = await signIn('wallet')

// Both access same account

Advanced Features

Biometric Auth (Mobile)

typescript
import { useBiometric } from '@civra/web3-mobile'

const { authenticate } = useBiometric()

// Require fingerprint/face ID
await authenticate({
  reason: 'Sign transaction',
  fallback: 'password'
})

Hardware Wallet Support

typescript
import { useLedger } from '@civra/web3'

const { connect, sign } = useLedger()

// Connect Ledger
await connect()

// Sign with hardware wallet
const signature = await sign(message)

Social Recovery

typescript
// Set recovery contacts
await setRecoveryContacts([
  '0x...', // Friend 1
  '0x...', // Friend 2
  '0x...'  // Friend 3
])

// Require 2 of 3 to recover
await recoverAccount({
  signatures: [sig1, sig2]
})

Testing Auth

Mock Wallet Connection

typescript
// In tests
import { mockWallet } from '@civra/web3/testing'

test('user can connect wallet', async () => {
  const { connect } = mockWallet({
    address: '0x123...',
    chainId: 1
  })

  await connect()
  expect(getAddress()).toBe('0x123...')
})

Test Networks

Use testnets for development:

typescript
const config = {
  // Development
  chains: [sepolia, mumbai],

  // Production
  // chains: [mainnet, polygon]
}

Next Steps

Built with Civra - Web3 Development Platform