Should we use Event Streams instead of Log Streams for MFA synchronization?

We’re currently using Log Streams and a webhook to react to MFA-related changes in Auth0.

While evaluating Event Streams, I noticed MFA changes seem to surface only as generic user.updated events, so we’d need to detect changes (e.g. multifactor_last_modified) and then call the Management API to determine the actual MFA state. Event Streams appear to be positioned for user lifecycle synchronization, while Log Streams are described as being primarily for monitoring and analytics.

For a production system that needs to keep MFA state synchronized with Auth0, would Auth0 recommend moving from Log Streams to Event Streams? If so, what are the advantages in this scenario? Is the intended pattern to react to user.updated and then query the Management API for current MFA methods?

Thanks!

Hi @Eugene.Kriuchkov

Welcome to the Auth0 Community!

You are evaluating whether to migrate from Log Streams to Event Streams for keeping MFA state synchronized with Auth0. You have observed that Event Streams surface MFA changes only as generic user.updated events, requiring you to query the Management API to determine actual MFA state, while Log Streams provide specific MFA event codes like gd_enrollment_complete and gd_unenroll.

Auth0 recommends Event Streams for user lifecycle synchronization, but for production systems that need to keep MFA state synchronized, Log Streams are better suited because they provide granular, MFA-specific event codes that directly indicate enrollment, unenrollment, and authentication changes. Event Streams are state-based and abstract away the specific trigger, which requires you to query the Management API to determine what actually changed. For MFA synchronization, Log Streams provide more actionable events without additional API calls.

Root Cause:

Event Streams and Log Streams serve different purposes:

  1. Event Streams — State-based notifications focused on user lifecycle (created, updated, deleted). They abstract away the specific trigger and focus on the fact that the user profile changed. This requires you to query the Management API to determine what changed.
  2. Log Streams — Trigger-based detailed audit logs that capture specific events, including granular MFA events like enrollment, unenrollment, and authentication success/failure. These events directly indicate what happened without requiring additional API calls.

For MFA synchronization specifically, Log Streams provide:

  • gd_enrollment_complete — MFA enrollment completed
  • gd_start_enroll — MFA enrollment started
  • gd_unenroll — MFA device unenrolled
  • gd_update_device_account — MFA device updated
  • gd_auth_succeed — MFA authentication success
  • gd_auth_failed — MFA authentication failed

Solution: Continue Using Log Streams for MFA Synchronization

Recommendation:

For a production system that needs to keep MFA state synchronized with Auth0, continue using Log Streams with your webhook. Log Streams are purpose-built for this use case because they:

  1. Provide specific MFA event codes — You can directly react to gd_enrollment_complete, gd_unenroll, and other MFA-specific events without querying the Management API
  2. Eliminate unnecessary API calls — You know exactly what changed from the event code alone
  3. Provide audit trail — All MFA changes are logged with timestamps and details
  4. Are designed for monitoring and analytics — Which aligns with your synchronization needs

Why Event Streams Are Not Ideal for MFA Synchronization:

  1. Generic user.updated events — You cannot determine what changed without querying the Management API
  2. Additional latency — You must make a Management API call to fetch current MFA methods after each event
  3. Potential race conditions — Between receiving the event and querying the API, the state may change again
  4. Designed for different use case — Event Streams are optimized for user lifecycle (provisioning/deprovisioning), not detailed state tracking

If You Must Use Event Streams:

If you decide to migrate to Event Streams for other reasons, the pattern would be:

  1. Subscribe to user.updated events
  2. On each event, call the Management API to fetch the current user's authentication methods:
GET /api/v2/users/{user_id}/authentication-methods
  1. Compare the returned methods with your local cache to determine what changed
  2. Update your system based on the differences

This approach works but requires additional API calls and introduces latency compared to Log Streams.

Best Practice:

For MFA synchronization in production:

  1. Continue using Log Streams with your webhook
  2. Subscribe to these MFA-specific event codes:
    • gd_enrollment_complete — User enrolled in MFA
    • gd_start_enroll — User started MFA enrollment
    • gd_unenroll — User unenrolled from MFA
    • gd_update_device_account — User updated MFA device
    • gd_auth_succeed — MFA authentication succeeded
    • gd_auth_failed — MFA authentication failed
  3. React directly to these events without querying the Management API
  4. Use Event Streams separately if you need general user lifecycle notifications (for provisioning/deprovisioning)

Example Log Stream Webhook Handler:

app.post('/webhook', (req, res) => {
  const event = req.body;
  
  // React to specific MFA events
  if (event.type === 'gd_enrollment_complete') {
    // User enrolled in MFA - update your system
    updateUserMfaStatus(event.user_id, 'enrolled');
  } else if (event.type === 'gd_unenroll') {
    // User unenrolled from MFA - update your system
    updateUserMfaStatus(event.user_id, 'unenrolled');
  } else if (event.type === 'gd_auth_succeed') {
    // MFA authentication succeeded - log or track
    logMfaSuccess(event.user_id);
  }
  
  res.status(200).send('OK');
});

Migration Path (If Needed):

If you need to migrate to Event Streams in the future:

  1. Keep Log Streams active during transition
  2. Implement Event Streams handler that queries Management API for MFA methods
  3. Validate that both systems produce the same results
  4. Once validated, deprecate Log Streams

For MFA state synchronization in production, Log Streams are the recommended approach because they provide specific, actionable events without requiring additional API calls.

Kind Regards,
Nik