Microsoft Graph subscriptions are sometimes lost silently

Faisal Maulana 0 Reputation points
2026-08-14T03:09:40.16+00:00

We use Microsoft Graph change notifications with resource data for Outlook mailbox, contacts, and calendar synchronization.

The synced account sometimes lose synchronization. We are investigating whether a reauthorizationRequired lifecycle notification can be delayed or missed before the subscription becomes inactive.

Subscriptions are created with a 3 days lifetime:

var expirationDateTime = DateTime.Now.AddDays(3);

var subscription = new Subscription
{
    ChangeType = changeType,
    NotificationUrl = "https://<domain>/v1/webhook/{resource}",
    LifecycleNotificationUrl = "https://<domain>/v1/webhook/lifecycle",
    ExpirationDateTime = expirationDateTime,
    ApplicationId = "<application-id>",
    CreatorId = "<creator-id>",
    EncryptionCertificate = "<certificate>",
    EncryptionCertificateId = "<certificate-id>",
    ClientState = "<client-state>",
    IncludeResourceData = true,
    Resource = resourcePath
};

var subscriptionResponse =
    await graphClient.Subscriptions.PostAsync(subscription);

We store the returned subscription ID and expiration time in our database.

Current lifecycle event handling

switch (notification.LifecycleEvent)
{
    case LifecycleEventType.ReauthorizationRequired:
        await RenewSubscription(subscriptionId);
        break;

    case LifecycleEventType.SubscriptionRemoved:
        await RecreateSubscription(subscriptionId);
        break;

    case LifecycleEventType.Missed:
        logger.LogWarning(
            "Missed notifications detected for subscription {SubscriptionId}",
            subscriptionId
        );
        break;
}

Intermittently, the sequence appears to be:

  1. The subscription is created successfully.
  2. Resource change notifications are received normally.
  3. Change notifications later stop arriving.
  4. The stored subscription expiration passes.

We would like to guarantee that:

  • Subscriptions are renewed before expiration.
  • A lost lifecycle event does not permanently stop synchronization.
  • Authentication failures are detected promptly so the user can reauthenticate.

Additional Questions

  1. Can webhook-delivery throttling delay or permanently drop a reauthorizationRequired lifecycle notification, or does throttling only apply to resource change notifications?
  2. If delivery of reauthorizationRequired fails, how long does Microsoft Graph retry it?
  3. Can a later missed lifecycle event indicate that a previous reauthorizationRequired lifecycle event was not delivered?
  4. Is the recommended resilient design to renew subscriptions proactively using a scheduled process, independently of lifecycle notifications, or every missed event to renew the subscription?
Microsoft Security | Microsoft Graph
0 comments No comments

1 answer

Sort by: Newest
  1. AI answer

    2026-08-14T03:10:09.28+00:00

    A resilient design should not rely only on lifecycle notifications.

    Supported facts from Microsoft Graph documentation:

    • reauthorizationRequired is sent when the access token is about to expire, when the subscription is about to expire, or when an administrator revoked the app’s permissions to read a resource.
    • Microsoft Graph sends that authorization challenge to the lifecycleNotificationUrl.
    • Change notifications can continue for a while after the challenge is sent, but eventually delivery pauses until the subscription is reauthorized or recreated.
    • Any resource changes that occur while delivery is paused and before the app successfully creates the subscription again are lost from webhook delivery and must be recovered separately, for example by using delta query.
    • reauthorizationRequired is supported for all resources.
    • missed means some change notifications were not delivered, for example because of throttling. The documented response is to acknowledge the event, validate it, and perform a full data resync of the resource, for example with delta query.
    • subscriptionRemoved means the subscription was removed and must be recreated.

    For the design goals listed:

    1. Renew subscriptions before expiration
      Use a scheduled renewal process based on the stored expirationDateTime, instead of waiting only for reauthorizationRequired. The documentation explicitly says to extend a subscription before it expires.
    2. Prevent permanent sync loss when a lifecycle event is lost
      Treat lifecycle notifications as recovery signals, not the only control plane. If notifications stop or a subscription expires or is removed, recreate or renew the subscription and resync the resource state with delta query to recover missed changes.
    3. Detect authentication failures promptly
      reauthorizationRequired is the documented signal for token-expiry, subscription-expiry, and permission-revocation conditions. subscriptionRemoved can also occur when access conditions change and the app may need a new access token before it can create a new subscription.

    Answers to the specific questions:

    1. The provided documentation does not state whether webhook throttling applies to reauthorizationRequired lifecycle notifications specifically, or only to resource change notifications.
    2. The provided documentation does not state how long Microsoft Graph retries delivery of a failed reauthorizationRequired lifecycle notification.
    3. A missed lifecycle event means some change notifications were not delivered. The documentation does not state that a later missed event specifically indicates an earlier reauthorizationRequired notification was not delivered.
    4. The documented resilient pattern is to renew subscriptions proactively before expiration and also handle lifecycle notifications. For missed, the documented action is full resync, not subscription renewal by itself. For reauthorizationRequired, acknowledge, validate, ensure a valid access token, and then either call POST /subscriptions/{id}/reauthorize or PATCH /subscriptions/{id}. If reauthorizing and renewing together, use a single PATCH /subscriptions/{id} with an updated expirationDateTime. Do not send POST /subscriptions/{id}/reauthorize and PATCH /subscriptions/{id} for the same subscription within a 10-minute window.

    A practical pattern for this scenario is:

    • Keep the stored subscription ID and expirationDateTime.
    • Run scheduled renewal before expiration.
    • Handle reauthorizationRequired immediately and resume the flow by reauthorizing or patching the subscription.
    • Handle subscriptionRemoved by creating a new subscription.
    • Handle missed by running a full resync or delta-based catch-up.
    • If notification delivery pauses or the subscription lapses, assume webhook gaps occurred and recover state from the resource directly.

    References:

    AI-generated content may be incorrect. Read our transparency notes for more information.

    Was this answer helpful?

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.