Authentication
The Loom Loyalty Hub uses WorkOS AuthKit for enterprise-grade authentication, supporting SSO, MFA, and user management.
Overview
Authentication in the Hub works as follows:
- User visits the Hub
- Hub loads tenant configuration (including WorkOS settings)
- User is redirected to WorkOS for authentication
- WorkOS returns an access token
- Hub uses the token for API requests
WorkOS Setup
1. Create a WorkOS Account
Sign up at workos.com and create an application.
2. Configure Your Application
In the WorkOS dashboard:
- Go to Authentication > AuthKit
- Enable AuthKit for your application
- Configure the redirect URI:
https://your-hub.pages.dev/auth/callback - Note your Client ID
3. Create an Organization
For each tenant:
- Go to Organizations
- Create a new organization
- Note the Organization ID
- Configure SSO connections if needed
4. Add to Tenant Config
Add WorkOS settings to your tenant configuration:
{
"workos": {
"clientId": "client_01HXYZ...",
"organizationId": "org_01HXYZ..."
}
}
Authentication Flow
Login
User visits Hub
│
▼
Hub loads config with WorkOS settings
│
▼
User clicks "Sign In"
│
▼
Redirect to WorkOS AuthKit
│
▼
User authenticates (SSO, password, etc.)
│
▼
WorkOS redirects back with code
│
▼
Hub exchanges code for tokens
│
▼
User is authenticated
Token Management
The Hub manages tokens automatically:
- Access Token - Short-lived, stored in memory
- Refresh Token - HTTP-only cookie for security
- Auto-refresh - Tokens are refreshed before expiry
Using Authentication
AuthProvider
The Hub wraps your application with AuthProvider:
import { AuthProvider } from "@workos-inc/authkit-react";
<ConfigProvider>
<AuthProvider clientId={config.workos.clientId} organizationId={config.workos.organizationId}>
<App />
</AuthProvider>
</ConfigProvider>;
useAuth Hook
Access authentication state in components:
import { useAuth } from "@workos-inc/authkit-react";
function UserMenu() {
const { user, isLoading, signIn, signOut } = useAuth();
if (isLoading) {
return <Skeleton className="h-8 w-8 rounded-full" />;
}
if (!user) {
return <Button onClick={() => signIn()}>Sign In</Button>;
}
return (
<DropdownMenu>
<DropdownMenuTrigger>
<Avatar>
<AvatarImage src={user.profilePictureUrl} />
<AvatarFallback>{user.firstName?.[0]}</AvatarFallback>
</Avatar>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>{user.email}</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => signOut()}>Sign Out</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
}
Protected Routes
Protect routes that require authentication:
import { useAuth } from "@workos-inc/authkit-react";
import { Navigate } from "@tanstack/react-router";
function ProtectedRoute({ children }: { children: React.ReactNode }) {
const { user, isLoading } = useAuth();
if (isLoading) {
return <LoadingScreen />;
}
if (!user) {
return <Navigate to="/login" />;
}
return children;
}
SSO Configuration
Supported Providers
WorkOS supports these SSO providers:
- Okta
- Azure AD
- Google Workspace
- OneLogin
- JumpCloud
- PingFederate
- Generic SAML 2.0
- Generic OIDC
Configuring SSO
- In WorkOS dashboard, go to the organization
- Add an SSO connection
- Follow the provider-specific setup guide
- Users from that domain will use SSO automatically
Domain Verification
To enable SSO for a domain:
- Add the domain to the organization
- Verify ownership via DNS TXT record
- Users with that email domain will use SSO
Multi-Factor Authentication
Enabling MFA
In WorkOS dashboard:
- Go to Authentication > MFA
- Enable MFA for your application
- Choose factors: TOTP, SMS, or both
MFA Flow
When MFA is required:
- User completes primary authentication
- WorkOS prompts for second factor
- User enters code from authenticator/SMS
- Authentication completes
Role-Based Access Control
User Roles
Define roles in WorkOS:
// Example roles
const roles = {
admin: ["read", "write", "delete", "manage_users"],
manager: ["read", "write"],
viewer: ["read"],
};
Checking Permissions
import { useAuth } from "@workos-inc/authkit-react";
function AdminPanel() {
const { user } = useAuth();
// Check user's role
const isAdmin = user?.role === "admin";
if (!isAdmin) {
return <div>Access denied</div>;
}
return <AdminDashboard />;
}
Development Mode
For local development without WorkOS:
Mock Authentication
Set VITE_USE_REAL_API=false to use mock authentication:
// Mock user is automatically provided
const mockUser = {
id: "user_mock",
email: "demo@example.com",
firstName: "Demo",
lastName: "User",
};
Bypassing Auth
In development, you can bypass authentication:
// In your auth provider
if (import.meta.env.DEV && !import.meta.env.VITE_WORKOS_CLIENT_ID) {
// Return mock auth state
return {
user: mockUser,
isLoading: false,
signIn: () => {},
signOut: () => {},
};
}
Security Best Practices
1. Use HTTPS
Always use HTTPS in production:
{
"workos": {
"redirectUri": "https://hub.example.com/auth/callback"
}
}
2. Validate Tokens
The SDK validates tokens automatically, but ensure:
- Token expiry is checked
- Audience matches your application
- Issuer is WorkOS
3. Secure Storage
- Never store tokens in localStorage
- Use HTTP-only cookies for refresh tokens
- Access tokens in memory only
4. Session Management
- Implement session timeout
- Force re-authentication for sensitive actions
- Clear tokens on sign out
Troubleshooting
"Invalid client_id"
Check that the client ID in your config matches WorkOS:
{
"workos": {
"clientId": "client_01HXYZ..." // Must match exactly
}
}
"Redirect URI mismatch"
Ensure the redirect URI is configured in WorkOS:
- Go to WorkOS dashboard
- Check Redirect URIs under AuthKit
- Add your Hub's callback URL
"Organization not found"
Verify the organization ID exists:
{
"workos": {
"organizationId": "org_01HXYZ..." // Must be a valid org
}
}
SSO Not Working
- Check domain verification status
- Verify SSO connection is active
- Check IdP configuration matches WorkOS