Skip to content

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:

typescript
// 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

javascript
// 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

javascript
// 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

javascript
// 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:

php
// 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;
}
html
<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:

typescript
// 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:

javascript
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:

javascript
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:

javascript
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:

javascript
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:

javascript
// 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",
});
typescript
// 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

bash
# .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 private

Avoid PII in Events

Don't include PII:

javascript
FanFestSDK.trackEvent({
  action: "purchase",
  metadata: {
    email: "user@example.com", // Don't include PII
    name: "John Doe",
  },
});

Use opaque identifiers:

javascript
FanFestSDK.trackEvent({
  action: "purchase",
  externalObjectId: "order-12345", // Use opaque IDs
  metadata: {
    amount: 99.99,
    currency: "USD",
  },
});

Secure Token Handling

javascript
// 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:

javascript
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

  1. Check console logs for authentication success/failure
  2. Verify network requests to FanFest API
  3. Test anonymous mode when SSO fails
  4. Validate user data in FanFest dashboard

Next Steps

Released under the MIT License.