authsafe-react
v0.0.5
Published
Official React SDK for AuthSafe. Provides reusable components, authentication hooks, and utilities to securely integrate AuthSafe into your React applications.
Downloads
5
Maintainers
Readme
AuthSafe React SDK
Official React SDK for AuthSafe — a secure, multi-tenant identity and access management platform with full OAuth 2.1 and OpenID Connect (OIDC) support.
Features
- ✅ OAuth 2.1 & OIDC Compliant - Full implementation using
oidc-client-ts - ✅ PKCE Support - Automatic Proof Key for Code Exchange (required by OAuth 2.1)
- ✅ Multiple Signin Methods - Redirect, Popup, and Silent refresh
- ✅ Token Management - Automatic token refresh with refresh tokens
- ✅ React Query Integration - Efficient user data caching and invalidation
- ✅ TypeScript First - Fully typed API for better DX
- ✅ Customizable Branding - Logo, theme, colors, and layout
- ✅ SSR Compatible - Works with Next.js and other SSR frameworks
- ✅ Secure Storage - sessionStorage for OIDC state, HTTP-only cookies for refresh tokens
Installation
npm install authsafe-reactOr with Yarn:
yarn add authsafe-reactQuick Start
1. Wrap Your App with AuthProvider
import { AuthProvider } from 'authsafe-react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<AuthProvider
config={{
clientId: "your-client-id",
redirectUri: "http://localhost:3000/callback",
scope: ["openid", "email", "profile", "offline_access"],
env: "development",
}}
>
<YourApp />
</AuthProvider>
</QueryClientProvider>
);
}2. Add Login Button
import { useLogin } from 'authsafe-react';
function LoginButton() {
const { signinRedirect, isLoading } = useLogin();
return (
<button onClick={() => signinRedirect()} disabled={isLoading}>
{isLoading ? "Redirecting..." : "Sign In with AuthSafe"}
</button>
);
}3. Handle OAuth Callback
// pages/Callback.tsx
import { useOAuthCallback, useAuth } from 'authsafe-react';
import { useNavigate } from 'react-router-dom';
import { useEffect } from 'react';
function CallbackPage() {
const { loading, error } = useOAuthCallback();
const { isAuthenticated } = useAuth();
const navigate = useNavigate();
useEffect(() => {
if (!loading && isAuthenticated) {
navigate('/dashboard');
}
}, [loading, isAuthenticated, navigate]);
if (loading) return <div>Authenticating...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>Success! Redirecting...</div>;
}4. Access User Information
import { useAuth } from 'authsafe-react';
function Dashboard() {
const { user, isAuthenticated, isLoading } = useAuth();
if (isLoading) return <div>Loading...</div>;
if (!isAuthenticated) return <div>Please sign in</div>;
return (
<div>
<h1>Welcome, {user?.email}!</h1>
<p>User ID: {user?.id}</p>
</div>
);
}5. Logout
import { useLogout } from 'authsafe-react';
function LogoutButton() {
const { signoutRedirect, isLoading } = useLogout();
return (
<button onClick={() => signoutRedirect()} disabled={isLoading}>
{isLoading ? "Logging out..." : "Sign Out"}
</button>
);
}Authentication Methods
Signin with Redirect (Recommended)
Full-page redirect to the authorization server:
const { signinRedirect } = useLogin();
// Basic signin
await signinRedirect();
// With extra parameters
await signinRedirect({
prompt: 'login', // Force re-authentication
login_hint: '[email protected]',
ui_locales: 'en-US',
});Signin with Popup
Opens a popup window for authentication:
const { signinPopup } = useLogin();
// Popup signin (doesn't reload the page)
await signinPopup();Logout Methods
const { signoutRedirect, signoutPopup, signoutLocal } = useLogout();
// Redirect to server logout endpoint
await signoutRedirect({
post_logout_redirect_uri: 'http://localhost:3000',
});
// Logout in popup
await signoutPopup();
// Local logout (doesn't contact server)
await signoutLocal();Token Management
Access Tokens in API Calls
import { useAuth } from 'authsafe-react';
function MyComponent() {
const { tokens } = useAuth();
const callApi = async () => {
const response = await fetch('/api/protected', {
headers: {
'Authorization': `Bearer ${tokens.accessToken}`,
},
});
return response.json();
};
return <button onClick={callApi}>Call API</button>;
}Token Refresh
const { refresh, tokens } = useAuth();
// Manual refresh
if (tokens.refreshToken) {
await refresh();
}Automatic Token Renewal
Enable in config:
<AuthProvider
config={{
clientId: "your-client-id",
redirectUri: "http://localhost:3000/callback",
automaticSilentRenew: true, // ✅ Enable auto-refresh
}}
>
<App />
</AuthProvider>User Query & Invalidation
Track User Authentication
import { useAuth } from 'authsafe-react';
function ProtectedRoute({ children }) {
const { isAuthenticated, isLoading } = useAuth();
if (isLoading) return <div>Loading...</div>;
if (!isAuthenticated) return <Navigate to="/login" />;
return children;
}Logout by Invalidating User Query
import { useLogout } from 'authsafe-react';
import { useQueryClient } from '@tanstack/react-query';
import { userQueryKeys } from 'authsafe-react';
function LogoutButton() {
const { signoutLocal } = useLogout();
const queryClient = useQueryClient();
const handleLogout = async () => {
await signoutLocal();
// Invalidate user query to trigger refetch
queryClient.invalidateQueries({ queryKey: userQueryKeys.all() });
};
return <button onClick={handleLogout}>Logout</button>;
}Advanced Usage
Direct OAuthService Access
import { useInternals } from 'authsafe-react';
function AdvancedComponent() {
const { oauthService } = useInternals();
const performSilentRefresh = async () => {
if (oauthService) {
const user = await oauthService.signinSilent();
console.log('Silently refreshed:', user);
}
};
return <button onClick={performSilentRefresh}>Silent Refresh</button>;
}Custom OAuthService Instance
import { OAuthService } from 'authsafe-react';
const oauthService = new OAuthService({
clientId: "your-client-id",
redirectUri: "http://localhost:3000/callback",
scope: ["openid", "email"],
authority: "https://custom-auth-server.com",
});
await oauthService.signinRedirect();Configuration Options
| Option | Type | Required | Default | Description |
|--------|------|----------|---------|-------------|
| clientId | string | ✅ | - | Your OAuth client ID |
| redirectUri | string | ✅ | - | Callback URL after authentication |
| scope | string[] | ❌ | ["openid", "email"] | OAuth scopes to request |
| env | "development" \| "production" | ❌ | "development" | Environment |
| authority | string | ❌ | Auto-detected | Custom OAuth server URL |
| popupRedirectUri | string | ❌ | Same as redirectUri | Popup callback URL |
| automaticSilentRenew | boolean | ❌ | false | Enable automatic token renewal |
API Reference
Hooks
useLogin()- Initiate signin flow (redirect or popup)useOAuthCallback()- Handle OAuth callback (redirect)useOAuthPopupCallback()- Handle OAuth callback (popup)useLogout()- Logout methods (redirect, popup, local)useAuth()- Access auth state, user, and tokensuseUserQuery()- Query user information
Services
OAuthService- Core OAuth/OIDC service using oidc-client-tsHttpService- HTTP client with auth headers
Components
AuthProvider- Context provider for authenticationProfile- Pre-built profile component
Documentation
- 📘 OIDC Usage Guide - Complete usage documentation
- 📝 Examples - Copy-paste examples for common scenarios
- 🔧 OAuth Implementation - Technical details
Security Features
- ✅ PKCE (RFC 7636) - Proof Key for Code Exchange (automatic)
- ✅ State Parameter - CSRF protection (automatic)
- ✅ Nonce - Replay protection for ID tokens (automatic)
- ✅ Token Validation - JWT signature and claims validation
- ✅ Secure Storage - sessionStorage for state, HTTP-only cookies for refresh tokens
- ✅ OAuth 2.1 - Latest OAuth security best practices
Browser Support
- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
Requirements
- React 18+
- Node.js 16+
- TypeScript 5+ (optional, but recommended)
Development
Install Dependencies
npm installStart Dev Server
npm run devBuild
npm run buildRun Tests
npm run testTroubleshooting
"State does not match" Error
- Ensure sessionStorage is enabled
- Don't refresh page during OAuth flow
- Verify redirect_uri matches exactly (including trailing slash)
Popup Blocked
- Allow popups for your domain
- Use redirect method as fallback
No Refresh Token
- Include
offline_accessscope in config
For more troubleshooting tips, see OIDC Usage Guide.
Support
- 📧 Email: [email protected]
- 📚 Documentation: https://docs.authsafe.io
- 🐛 Issues: https://github.com/authsafe/authsafe-react/issues
License
Proprietary License © 2025 AuthSafe. All rights reserved.
Built with ❤️ by the AuthSafe Team
