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

**URL:** <https://community.auth0.com/t/should-we-use-event-streams-instead-of-log-streams-for-mfa-synchronization/203753>\
**Category:** Get Help\
**Tags:** log-stream, event-stream\
**Created:** [September 28, 2026, 10:07pm UTC](https://community.auth0.com/t/should-we-use-event-streams-instead-of-log-streams-for-mfa-synchronization/203753 "2026-09-28T22:07:32Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Eugene.Kriuchkov](https://sea1.discourse-cdn.com/auth0/user_avatar/community.auth0.com/eugene.kriuchkov/32/80994_2.png) [@Eugene.Kriuchkov](https://community.auth0.com/u/Eugene.Kriuchkov)\
**Post date:** [September 28, 2026, 10:07pm UTC](https://community.auth0.com/t/should-we-use-event-streams-instead-of-log-streams-for-mfa-synchronization/203753/1 "2026-09-28T22:07:33Z")

</div>

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!

---

<div class="post-metadata">

**Author:** ![nik.baleca](https://sea1.discourse-cdn.com/auth0/user_avatar/community.auth0.com/nik.baleca/32/68749_2.png) [@nik.baleca](https://community.auth0.com/u/nik.baleca)\
**Post date:** [September 29, 2026, 8:01pm UTC](https://community.auth0.com/t/should-we-use-event-streams-instead-of-log-streams-for-mfa-synchronization/203753/3 "2026-09-29T20:01:28Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/auth0/original/3X/b/5/b560f266932fcce5d57f09a6595bd50518cae3f3.jpeg) [@system](https://community.auth0.com/u/system)\
**Post date:** [October 9, 2026, 8:02pm UTC](https://community.auth0.com/t/should-we-use-event-streams-instead-of-log-streams-for-mfa-synchronization/203753/4 "2026-10-09T20:02:12Z")

</div>

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
