Skip to Content
⚠️ Note: Some details in this documentation may not be fully accurate yet.
GuideReact Integration

React Integration Guide - Solana

This guide shows how to integrate Alien Solana SSO into React applications using the React SDK with Solana wallet adapters.

Requirements

  • React 19.1.1 or higher
  • React DOM 19.1.1 or higher
  • @solana/web3.js ^1.95.0 or higher
  • @solana/wallet-adapter-react ^0.15.0 or higher
  • A modern web browser with JavaScript enabled
  • localStorage and sessionStorage support
  • A registered provider from the dev portal, with provider address

Installation

npm install @alien_org/solana-sso-sdk-react @solana/web3.js @solana/wallet-adapter-react

The React SDK requires Solana wallet adapter packages as peer dependencies.

Setup

Alien Solana SSO Provider

Wrap your app with both wallet adapter providers and AlienSolanaSsoProvider:

import { AlienSolanaSsoProvider } from '@alien_org/solana-sso-sdk-react'; function App() { return ( <WalletContextProvider> <AlienSolanaSsoProvider config={{ ssoBaseUrl: 'https://sso.alien-api.com', providerAddress: 'your-provider-address' }} > <YourApp /> </AlienSolanaSsoProvider> </WalletContextProvider> ); } export default App;

Configuration Options

  • ssoBaseUrl (required): Base URL of the SSO service
  • providerAddress (required): Your provider address from dev portal
  • pollingInterval (optional): Polling interval in milliseconds (default: 5000)
  • credentialSignerProgramId (optional): Credential Signer program ID
  • sessionRegistryProgramId (optional): Session Registry program ID
  • sasProgramId (optional): SAS program ID

Using the useSolanaAuth Hook

The useSolanaAuth() hook provides access to Solana authentication state and methods.

import { useSolanaAuth } from '@alien_org/solana-sso-sdk-react'; function Dashboard() { const { auth, wallet, logout } = useSolanaAuth(); if (!auth.sessionAddress) { return <div>Not authenticated</div>; } return ( <div> <p>Wallet: {wallet.publicKey?.toBase58()}</p> <p>Session: {auth.sessionAddress}</p> <button onClick={logout}>Logout</button> </div> ); }

Auth State

The auth object contains:

{ sessionAddress: string | null; }

Available Properties and Methods

const { client, // Direct access to AlienSolanaSsoClient instance auth, // Authentication state wallet, // Solana wallet adapter connectionAdapter, // Solana connection from context queryClient, // React Query client instance generateDeeplink, // Generate authentication deep link pollAuth, // Poll for authentication status verifyAttestation, // Verify on-chain attestation logout, // Clear authentication state openModal, // Open built-in Solana sign-in modal closeModal, // Close sign-in modal isModalOpen // Modal open state } = useSolanaAuth();

Using Pre-built Components

SolanaSignInButton

A pre-styled button that opens the Solana sign-in modal.

import { SolanaSignInButton } from '@alien_org/solana-sso-sdk-react'; import { useWallet } from '@solana/wallet-adapter-react'; import { WalletMultiButton } from '@solana/wallet-adapter-react-ui'; function LoginPage() { const { connected } = useWallet(); if (!connected) { return ( <div> <h1>Connect Your Wallet</h1> <WalletMultiButton /> </div> ); } return ( <div> <h1>Sign In with Alien</h1> <SolanaSignInButton /> </div> ); }

SolanaSignInModal

The modal is automatically rendered by AlienSolanaSsoProvider and handles:

  • QR code display
  • Polling for authentication
  • Transaction building and signing
  • On-chain attestation creation

Control it via the useSolanaAuth() hook:

import { useSolanaAuth } from '@alien_org/solana-sso-sdk-react'; function CustomButton() { const { openModal } = useSolanaAuth(); return <button onClick={openModal}>Sign In</button>; }

Complete Example

import { ConnectionProvider, WalletProvider } from '@solana/wallet-adapter-react'; import { WalletModalProvider, WalletMultiButton } from '@solana/wallet-adapter-react-ui'; import { AlienSolanaSsoProvider, useSolanaAuth, SolanaSignInButton } from '@alien_org/solana-sso-sdk-react'; import { useWallet } from '@solana/wallet-adapter-react'; import { clusterApiUrl } from '@solana/web3.js'; import { useMemo } from 'react'; import '@solana/wallet-adapter-react-ui/styles.css'; function App() { const endpoint = useMemo(() => clusterApiUrl('mainnet-beta'), []); return ( <ConnectionProvider endpoint={endpoint}> <WalletProvider wallets={[]} autoConnect> <WalletModalProvider> <AlienSolanaSsoProvider config={{ ssoBaseUrl: 'https://sso.alien-api.com', providerAddress: 'your-provider-address', }} > <Dashboard /> </AlienSolanaSsoProvider> </WalletModalProvider> </WalletProvider> </ConnectionProvider> ); } function Dashboard() { const { connected } = useWallet(); const { auth, logout } = useSolanaAuth(); if (!connected) { return ( <div> <h1>Connect Wallet</h1> <WalletMultiButton /> </div> ); } if (!auth.sessionAddress) { return ( <div> <h1>Sign In</h1> <SolanaSignInButton /> </div> ); } return ( <div> <h1>Dashboard</h1> <p>Session: {auth.sessionAddress}</p> <button onClick={logout}>Logout</button> </div> ); } export default App;

Custom Authentication Flow

If you want to implement a custom UI:

import { useSolanaAuth } from '@alien_org/solana-sso-sdk-react'; import { useWallet } from '@solana/wallet-adapter-react'; import { useState, useEffect } from 'react'; import QRCode from 'react-qr-code'; function CustomAuth() { const { wallet, generateDeeplink, pollAuth } = useSolanaAuth(); const [deepLink, setDeepLink] = useState<string | null>(null); const [pollingCode, setPollingCode] = useState<string | null>(null); const handleSignIn = async () => { if (!wallet.publicKey) return; const response = await generateDeeplink(wallet.publicKey.toBase58()); setDeepLink(response.deep_link); setPollingCode(response.polling_code); }; useEffect(() => { if (!pollingCode) return; const interval = setInterval(async () => { const response = await pollAuth(pollingCode); if (response.status === 'authorized') { clearInterval(interval); // The provider will automatically handle transaction creation and signing setDeepLink(null); setPollingCode(null); } else if (response.status === 'rejected' || response.status === 'expired') { clearInterval(interval); alert(`Authentication ${response.status}`); setDeepLink(null); setPollingCode(null); } }, 5000); return () => clearInterval(interval); }, [pollingCode, pollAuth]); if (deepLink) { return ( <div> <h2>Scan QR Code</h2> <QRCode value={deepLink} /> </div> ); } return <button onClick={handleSignIn}>Sign In with Alien</button>; }

Protected Routes

Create a protected route component:

import { useSolanaAuth } from '@alien_org/solana-sso-sdk-react'; import { useWallet } from '@solana/wallet-adapter-react'; import { Navigate } from 'react-router-dom'; function ProtectedRoute({ children }: { children: React.ReactNode }) { const { connected } = useWallet(); const { auth } = useSolanaAuth(); if (!connected) { return <Navigate to="/connect-wallet" />; } if (!auth.sessionAddress) { return <Navigate to="/sign-in" />; } return <>{children}</>; } // Usage <Route path="/dashboard" element={ <ProtectedRoute> <Dashboard /> </ProtectedRoute> } />

Grace Period Mechanism

The Solana provider implements a 60-second grace period after attestation creation to handle RPC indexing delays:

// After successful attestation creation // Session address is cached for 60 seconds // verifyAttestation() returns cached value immediately // Background verification runs after grace period expires

Storage keys:

  • alien-sso_solana_authed_address - Authenticated Solana address
  • alien-sso_session_address - Session address
  • alien-sso_attestation_created_at - Timestamp of attestation creation

Verifying Attestation on Mount

import { useSolanaAuth } from '@alien_org/solana-sso-sdk-react'; import { useWallet } from '@solana/wallet-adapter-react'; import { useEffect, useState } from 'react'; function App() { const { wallet } = useWallet(); const { verifyAttestation, auth } = useSolanaAuth(); const [isVerifying, setIsVerifying] = useState(true); useEffect(() => { const verify = async () => { if (wallet.publicKey) { await verifyAttestation(wallet.publicKey.toBase58()); } setIsVerifying(false); }; verify(); }, [wallet.publicKey]); if (isVerifying) { return <div>Verifying authentication...</div>; } return auth.sessionAddress ? <Dashboard /> : <LoginPage />; }

TypeScript Support

The React SDK is fully typed:

import type { SolanaAuthState, AlienSolanaSsoClient } from '@alien_org/solana-sso-sdk-react'; const auth: SolanaAuthState = useSolanaAuth().auth; const client: AlienSolanaSsoClient = useSolanaAuth().client;

Next Steps

Last updated on