private async Task <Subscription> CreateSubscription(string userId, string tenantId, string clientState, GraphServiceClient graphClient)
        {
            string encryptionCertificate = subscriptionOptions.Value.IncludeResourceData ? await keyVaultManager.GetEncryptionCertificate().ConfigureAwait(false) : null;

            string encryptionCertificateId = subscriptionOptions.Value.IncludeResourceData ? await keyVaultManager.GetEncryptionCertificateId().ConfigureAwait(false) : null;

            var newSubscription = await graphClient.Subscriptions.Request().AddAsync(new Subscription
            {
                Resource                = subscriptionOptions.Value.Resource,
                ChangeType              = subscriptionOptions.Value.ChangeType,
                NotificationUrl         = subscriptionOptions.Value.NotificationUrl,
                ClientState             = clientState,
                ExpirationDateTime      = DateTime.UtcNow + new TimeSpan(0, 0, 15, 0), // 4230 minutes is the current max lifetime, shorter duration useful for testing
                EncryptionCertificate   = encryptionCertificate,
                EncryptionCertificateId = encryptionCertificateId,
                IncludeResourceData     = subscriptionOptions.Value.IncludeResourceData
            });


            // This sample temporarily stores the subscription data, but production apps will likely use some method of persistent storage.
            // This sample stores the client state to validate the subscription, the tenant ID to reuse tokens, and the user ID to filter
            // messages to display by user.
            subscriptionStore.SaveSubscriptionInfo(Guid.Parse(newSubscription.Id),
                                                   newSubscription.ClientState,
                                                   userId,
                                                   tenantId);

            return(newSubscription);
        }
        public async Task <IActionResult> Create()
        {
            string userId      = User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier")?.Value;
            string tenantId    = User.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid")?.Value;
            string clientState = Guid.NewGuid().ToString();

            // Initialize the GraphServiceClient.
            var graphClient = await GraphServiceClientFactory.GetAuthenticatedGraphClient(async() =>
            {
                string result = await tokenAcquisition.GetAccessTokenOnBehalfOfUser(
                    HttpContext, new[] { Infrastructure.Constants.ScopeMailRead });
                return(result);
            });

            Subscription newSubscription = new Subscription();

            try
            {
                // Create a subscription.
                // The `Resource` property targets the `users/{user-id}` or `users/{user-principal-name}` path (not `me`) when using application permissions.
                // The NotificationUrl requires the `https` protocol and supports custom query parameters.

                newSubscription = await graphClient.Subscriptions.Request().AddAsync(new Subscription
                {
                    Resource        = $"users/{userId}/mailFolders('Inbox')/messages",
                    ChangeType      = "created",
                    NotificationUrl = appSettings.NotificationUrl,
                    ClientState     = clientState,
                    //ExpirationDateTime = DateTime.UtcNow + new TimeSpan(0, 0, 4230, 0) // current maximum lifespan for messages
                    ExpirationDateTime = DateTime.UtcNow + new TimeSpan(0, 0, 15, 0)     // shorter duration useful for testing
                });

                // Verify client state, then store the subscription ID and client state to validate incoming notifications.
                if (newSubscription.ClientState == clientState)
                {
                    // This sample temporarily stores the subscription data, but production apps will likely use some method of persistent storage.
                    // This sample stores the client state to validate the subscription, the tenant ID to reuse tokens, and the user ID to filter
                    // messages to display by user.
                    subscriptionStore.SaveSubscriptionInfo(newSubscription.Id,
                                                           newSubscription.ClientState,
                                                           userId,
                                                           tenantId);
                }
                else
                {
                    ViewBag.Message = "Warning! Mismatched client state.";
                }
            }
            catch (Exception e)
            {
                // If a tenant admin hasn't granted consent, this operation returns an Unauthorized error.
                // This sample caches the initial unauthorized token, so you'll need to start a new browser session.
                ViewBag.Message = BuildErrorMessage(e);
                return(View("Error"));
            }

            return(View("Subscription", newSubscription));
        }