Skip to Content
⚠️ Note: Some details in this documentation may not be fully accurate yet.
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