Skip to Content
GuideReact Integration

React Integration Guide

This guide shows how to integrate Alien SSO into React applications using the React SDK with pre-built hooks and components.

Requirements

  • React 19.1.1 or higher
  • React DOM 19.1.1 or higher
  • A registered provider from the developer portal with provider address

Installation

npm install @alien_org/sso-sdk-react

The React SDK automatically includes @alien_org/sso-sdk-core as a dependency.

Setup

Wrap Your App with Provider

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

Configuration Options

OptionTypeRequiredDescription
ssoBaseUrlstringYesBase URL of the SSO service
providerAddressstringYesYour provider address from developer portal
pollingIntervalnumberNoPolling interval in ms (default: 5000)

Using the useAuth Hook

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

import { useAuth } from '@alien_org/sso-sdk-react'; function Dashboard() { const { auth, logout } = useAuth(); if (!auth.isAuthenticated) { return <div>Not authenticated</div>; } return ( <div> <p>User ID: {auth.tokenInfo?.sub}</p> <p>Expires: {new Date(auth.tokenInfo.exp * 1000).toLocaleString()}</p> <button onClick={logout}>Logout</button> </div> ); }

Auth State

The auth object contains:

{ isAuthenticated: boolean; token: string | null; // Access token tokenInfo: { iss: string; // Issuer sub: string; // User identifier aud: string | string[]; // Audience (your provider address) exp: number; // Expiration timestamp iat: number; // Issued at timestamp nonce?: string; auth_time?: number; } | null; }

Available Methods

const { client, // Direct access to AlienSsoClient instance auth, // Authentication state queryClient, // React Query client instance generateDeeplink, // Generate authentication deep link pollAuth, // Poll for authentication status exchangeToken, // Exchange authorization code for tokens verifyAuth, // Verify current token (calls /oauth/userinfo) refreshToken, // Refresh access token logout, // Clear authentication state openModal, // Open built-in sign-in modal closeModal, // Close sign-in modal isModalOpen // Modal open state } = useAuth();

Using Pre-built Components

SignInButton

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

import { SignInButton } from '@alien_org/sso-sdk-react'; function LoginPage() { return ( <div> <h1>Welcome</h1> <SignInButton /> </div> ); }

SignInModal

The modal is automatically rendered by AlienSsoProvider and handles the complete authentication flow including QR code display, polling, and token exchange.

Control it via the useAuth() hook:

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

Token Refresh

The SDK provides a refreshToken method for refreshing access tokens:

import { useAuth } from '@alien_org/sso-sdk-react'; function MyComponent() { const { refreshToken, auth, logout } = useAuth(); async function handleApiCall() { // Check if token is expiring soon if (auth.tokenInfo && auth.tokenInfo.exp * 1000 < Date.now() + 60000) { const success = await refreshToken(); if (!success) { // Refresh failed, redirect to login return; } } // Make API call with fresh token const response = await fetch('/api/data', { headers: { Authorization: `Bearer ${auth.token}` } }); } }

Automatic Token Refresh with Axios

For automatic token refresh on API calls, use an axios interceptor:

import { useAuth } from '@alien_org/sso-sdk-react'; import axios from 'axios'; import { useMemo, useRef } from 'react'; export function useAxios() { const { auth, logout, refreshToken } = useAuth(); const isRefreshing = useRef(false); const failedQueue = useRef([]); return useMemo(() => { const instance = axios.create({ baseURL: '/api', }); // Add token to requests instance.interceptors.request.use((config) => { if (auth.token) { config.headers.Authorization = `Bearer ${auth.token}`; } return config; }); // Handle 401 responses instance.interceptors.response.use( (response) => response, async (error) => { const originalRequest = error.config; if (error.response?.status !== 401 || originalRequest._retry) { return Promise.reject(error); } if (isRefreshing.current) { // Queue request while refreshing return new Promise((resolve, reject) => { failedQueue.current.push({ resolve, reject }); }).then(() => instance(originalRequest)); } originalRequest._retry = true; isRefreshing.current = true; try { const success = await refreshToken(); if (success) { failedQueue.current.forEach((p) => p.resolve()); failedQueue.current = []; return instance(originalRequest); } throw new Error('Refresh failed'); } catch (refreshError) { failedQueue.current.forEach((p) => p.reject(refreshError)); failedQueue.current = []; logout(); return Promise.reject(refreshError); } finally { isRefreshing.current = false; } } ); return instance; }, [auth.token, logout, refreshToken]); }

Custom Authentication Flow

If you want to implement a custom UI instead of using the built-in modal:

import { useAuth } from '@alien_org/sso-sdk-react'; import { useState, useEffect } from 'react'; import QRCode from 'qrcode.react'; function CustomAuth() { const { generateDeeplink, pollAuth, exchangeToken, auth } = useAuth(); const [deepLink, setDeepLink] = useState<string | null>(null); const [pollingCode, setPollingCode] = useState<string | null>(null); const handleSignIn = async () => { const response = await generateDeeplink(); 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); await exchangeToken(response.authorization_code!); setDeepLink(null); setPollingCode(null); } else if (response.status === 'rejected' || response.status === 'expired') { clearInterval(interval); setDeepLink(null); setPollingCode(null); } }, 5000); return () => clearInterval(interval); }, [pollingCode, pollAuth, exchangeToken]); if (auth.isAuthenticated) { return <div>Authenticated as {auth.tokenInfo?.sub}</div>; } if (deepLink) { return ( <div> <QRCode value={deepLink} size={256} /> <p>Scan with Alien App</p> </div> ); } return <button onClick={handleSignIn}>Sign In with Alien</button>; }

Protected Routes

Create a protected route component:

import { useAuth } from '@alien_org/sso-sdk-react'; import { Navigate } from 'react-router-dom'; function ProtectedRoute({ children }: { children: React.ReactNode }) { const { auth } = useAuth(); if (!auth.isAuthenticated) { return <Navigate to="/login" />; } return <>{children}</>; } // Usage <Route path="/dashboard" element={ <ProtectedRoute> <Dashboard /> </ProtectedRoute> } />

Complete Example

import { AlienSsoProvider, useAuth, SignInButton } from '@alien_org/sso-sdk-react'; import { useEffect } from 'react'; function App() { return ( <AlienSsoProvider config={{ ssoBaseUrl: 'https://sso.alien-api.com', providerAddress: 'your-provider-address' }} > <Dashboard /> </AlienSsoProvider> ); } function Dashboard() { const { auth, logout, verifyAuth } = useAuth(); // Verify token on mount useEffect(() => { if (auth.token) { verifyAuth(); } }, []); if (!auth.isAuthenticated) { return ( <div> <h1>Welcome to My App</h1> <SignInButton /> </div> ); } return ( <div> <h1>Dashboard</h1> <p>User ID: {auth.tokenInfo?.sub}</p> <p>Issuer: {auth.tokenInfo?.iss}</p> <p>Expires: {new Date(auth.tokenInfo!.exp * 1000).toLocaleString()}</p> <button onClick={logout}>Logout</button> </div> ); } export default App;

TypeScript Support

The React SDK is fully typed. Import types as needed:

import type { AlienSsoClient } from '@alien_org/sso-sdk-react'; import type { AuthorizeResponse, PollResponse, TokenResponse, TokenInfo, } from '@alien_org/sso-sdk-core';

Next Steps

Last updated on