SSO Integration
The FanFest SDK integrates with your existing authentication system to provide seamless user experiences and personalized rewards.
What the SDK Needs
The SDK requires minimal user information:
- User ID - Unique identifier from your system
- Email (optional) - For reward notifications
- Display Name (optional) - For personalized experiences
- SSO Token - For secure authentication
Complete OIDC Integration
Here's how to set up OIDC authentication with environment configuration:
// Nuxt.js configuration with OIDC
export default defineNuxtConfig({
runtimeConfig: {
auth: {
oidc: {
session: {
name: "fanfestfc-oidc",
password: process.env.NUXT_OIDC_AUTH_SESSION_SECRET,
maxAge: 60 * 60 * 24 * 30, // 30 days
secure: process.env.NODE_ENV === "production",
sameSite: "lax",
},
},
auth0: {
clientId: process.env.NUXT_OIDC_PROVIDERS_AUTH0_CLIENT_ID,
clientSecret: process.env.NUXT_OIDC_PROVIDERS_AUTH0_CLIENT_SECRET,
baseUrl: process.env.NUXT_OIDC_PROVIDERS_AUTH0_BASE_URL,
},
},
public: {
apiUrl: process.env.API_URL,
apiKey: process.env.API_KEY, // Safe to expose - scoped to origin
appOrigin: process.env.APP_ORIGIN ?? "https://fanfest.vip",
},
},
});Supported Integration Patterns
Auth0 Integration
// Using Auth0's getAccessTokenSilently
FanFestSDK.init({
apiKey: "your-api-key",
clientId: "your-client-id",
hostLoginFn: async () => {
const token = await auth0.getAccessTokenSilently();
return {
token,
userId: auth0.user.sub,
email: auth0.user.email,
displayName: auth0.user.name,
};
},
});Keycloak Integration
// Using Keycloak's token
FanFestSDK.init({
apiKey: "your-api-key",
clientId: "your-client-id",
hostLoginFn: async () => {
if (keycloak.authenticated) {
return {
token: keycloak.token,
userId: keycloak.subject,
email: keycloak.tokenParsed.email,
displayName: keycloak.tokenParsed.name,
};
}
return null;
},
});Generic OIDC Integration
// Custom OIDC provider
FanFestSDK.init({
apiKey: "your-api-key",
clientId: "your-client-id",
hostLoginFn: async () => {
const token = await getOIDCToken();
const userInfo = await getUserInfo(token);
return {
token,
userId: userInfo.sub,
email: userInfo.email,
displayName: userInfo.name,
};
},
});WordPress Integration
For WordPress sites, you can surface user information safely:
// In your WordPress theme
function fanfest_user_data() {
if (is_user_logged_in()) {
$user = wp_get_current_user();
return [
'userId' => $user->ID,
'email' => $user->user_email,
'displayName' => $user->display_name
];
}
return null;
}<script>
FanFestSDK.init({
apiKey: "your-api-key",
clientId: "your-client-id",
hostLoginFn: () => {
const userData = window.fanfestUserData;
return userData
? {
token: userData.nonce, // WordPress nonce
userId: userData.userId,
email: userData.email,
displayName: userData.displayName,
}
: null;
},
});
</script>Complete Integration with Action Mapping
Here's a complete integration example with action mapping and custom handlers:
// Action mapping for engagement tracking
const engagementActionToChannelActionId: Record<EngagementAction, string> = {
[EngagementAction.PURCHASED_ITEM]: "fanfestfc_PURCHASED_ITEM",
[EngagementAction.PODCAST_COMPLETE]: "fanfestfc_PODCAST_COMPLETE",
[EngagementAction.BROWSED_TICKETS]: "fanfestfc_BROWSED_TICKETS",
[EngagementAction.LOCATION_CHECK_IN]: "fanfestfc_LOCATION_CHECK_IN",
[EngagementAction.NEWSLETTER_SIGNUP]: "fanfestfc_NEWSLETTER_SIGNUP",
[EngagementAction.VIDEO_WATCH]: "fanfestfc_VIDEO_WATCH",
[EngagementAction.ARTICLE_READING]: "fanfestfc_ARTICLE_READING",
[EngagementAction.PLAYED_GAME]: "fanfestfc_PLAYED_GAME",
// ... more actions
};
// Register action mapping
FanFestSDK.registerActionMapping(engagementActionToChannelActionId);
// Initialize with custom handlers
FanFestSDK.init({
clientId: "fanfestfc",
apiKey: config.public.apiKey,
apiBase: config.public.apiUrl,
appOrigin: config.public.appOrigin,
iframe: {
backgroundColor: "var(--color-brand-950)",
},
hostLoginFn: () => {
// Triggers login on the host website
authStore.login();
},
hostRewardsFn: () => {
// Navigates to the rewards page/section that embeds FanFest
router.push("/rewards");
},
});Host Function Handlers
hostLoginFn - Host Website Login
The hostLoginFn is called when the SDK needs to trigger authentication on your host website:
FanFestSDK.init({
apiKey: "your-api-key",
clientId: "your-client-id",
hostLoginFn: () => {
// Trigger login on your host website
// This could be:
// - Redirect to login page
// - Open login modal
// - Trigger OAuth flow
window.location.href = "/login";
// or
openLoginModal();
// or
initiateOAuthFlow();
},
});hostRewardsFn - Navigate to Rewards Section
The hostRewardsFn is called when the SDK needs to navigate to your rewards page or section:
FanFestSDK.init({
apiKey: "your-api-key",
clientId: "your-client-id",
hostRewardsFn: () => {
// Navigate to your rewards page/section
// This is typically where you embed the FanFest rewards interface
window.location.href = "/rewards";
// or
router.push("/rewards");
// or
showRewardsSection();
},
});Error Handling & Fallbacks
Authentication Failures
The SDK gracefully handles authentication failures:
FanFestSDK.init({
apiKey: "your-api-key",
clientId: "your-client-id",
hostLoginFn: async () => {
try {
const token = await getAuthToken();
return { token, userId: getUserId() };
} catch (error) {
console.warn("SSO authentication failed, continuing anonymously");
return null; // SDK continues in anonymous mode
}
},
});Token Refresh
For long-lived sessions, implement token refresh:
FanFestSDK.init({
apiKey: "your-api-key",
clientId: "your-client-id",
hostLoginFn: async () => {
const token = await getValidToken(); // Your token refresh logic
return token ? { token, userId: getUserId() } : null;
},
});Security Best Practices
API Key Handling
✅ FanFest API keys are origin-scoped and safe for client-side use:
// API keys are scoped to your domain origin - safe to expose
FanFestSDK.init({
apiKey: "your-fanfest-api-key", // Origin-scoped, safe for client-side
clientId: "your-client-id",
});// Environment-based configuration
const config = useRuntimeConfig();
FanFestSDK.init({
apiKey: config.public.apiKey, // Public config - origin-scoped
clientId: "fanfestfc",
apiBase: config.public.apiUrl,
appOrigin: config.public.appOrigin,
});Environment Configuration
# .env file - public variables are safe for client exposure
API_URL=https://api.staging.fanfest.vip
API_KEY=your-fanfest-api-key # Origin-scoped, safe to expose
APP_ORIGIN=https://fanfest.vip
NUXT_OIDC_AUTH_SESSION_SECRET=your-secret-key # Keep this privateAvoid PII in Events
❌ Don't include PII:
FanFestSDK.trackEvent({
action: "purchase",
metadata: {
email: "user@example.com", // Don't include PII
name: "John Doe",
},
});✅ Use opaque identifiers:
FanFestSDK.trackEvent({
action: "purchase",
externalObjectId: "order-12345", // Use opaque IDs
metadata: {
amount: 99.99,
currency: "USD",
},
});Secure Token Handling
// Store tokens securely
const getAuthToken = async () => {
// Use secure storage (httpOnly cookies, secure localStorage)
const token = await secureStorage.get("auth_token");
if (isTokenExpired(token)) {
return await refreshToken();
}
return token;
};Testing SSO Integration
Development Mode
Enable debug logging to verify authentication:
FanFestSDK.init({
apiKey: "your-api-key",
clientId: "your-client-id",
hostLoginFn: async () => {
const authData = await getAuthData();
console.log("SSO Auth Data:", authData);
return authData;
},
});Verification Steps
- Check console logs for authentication success/failure
- Verify network requests to FanFest API
- Test anonymous mode when SSO fails
- Validate user data in FanFest dashboard
Next Steps
- API Reference - Complete method documentation
- Examples - Implementation patterns
- Architecture - System architecture
