MicrosoftEdge / pushnotifications-demo-aspnetcore

Demo for cross-browser push notifications with ASP.NET Core server side code
Apache License 2.0
47 stars 21 forks source link

WebPush Notification Send Results in 403 #1

Open iseec opened 5 years ago

iseec commented 5 years ago

Hello

I used your demo as a blueprint to implement the push subscriptions for our customers.

I can subscribe users, and also send notifications to them in my development environment. So i pushed it up to staging, but now i get the 403 with the same code. (with new subscriptions for the new environment).

Exception: Received unexpected response code: 403 at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() --- End of stack trace from previous location where exception was thrown --- at WebPush.WebPushClient.HandleResponse(HttpResponseMessage response, PushSubscription subscription) at WebPush.WebPushClient.<SendNotificationAsync>d__15.MoveNext() at WebPush.WebPushClient.<SendNotificationAsync>d__16.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Backend.Notifications.MessageHandler.NotificationBatchMessageHandler.<Handle>d__11.MoveNext() in /app/src/Backend/Notifications/MessageHandler/NotificationBatchMessageHandler.cs:line 93

For the Subscriptions, they are done via a website run in docker containers behind a Loadbalancer, the public endpoint of the Loadbalancer is served via Https, and the containers run on different machines in a private subnet.

The Communication between the Loadbalancers and Containers is established via HTTP.

Code to send Notifications:

    var notification = GenerateNotification(batch.Template, account);
    string notificationjson = string.Empty;
    try
    {
        if (await _repo.RecordNotificationSent(subscription.Id, batch.Template.Id, 
    notification.NotificationId.ToString()))
        {
            notificationjson = JsonConvert.SerializeObject(notification);
            _client = new WebPushClient();
            await _client.SendNotificationAsync(ToWebPushSubscription(subscription),
                     notificationjson, _vapidDetails);
        }

    }
    catch (WebPushException ex)
    {

        if(ex.Message == "Subscription no longer valid")
        {
            Logger?.LogInformation($"invalidate subscription {subscription.Id}");
            await _ar.UnsubscribePushAsync(subscription);
        }
        else
        {
            Logger?.LogCritical(ex.Message, ex);
        }
    }
    catch (Exception ex)
    {
        Logger?.LogCritical(ex.Message, ex);
    }
    ...
    private WebPush.PushSubscription ToWebPushSubscription(PushSubscription sub)
    {
        return new WebPush.PushSubscription(sub.Endpoint, sub.P256Dh, sub.Auth);
    }

Environment Settings:

Development Environment:

Staging Environment:

WebServer: Kestrel

Any Ideas what could cause this issue, and how to fix it?

mark-szabo commented 5 years ago

Hi @epandasa, have you generated new VAPID keys for your staging environment?

iseec commented 5 years ago

Hi @mark-szabo,

i just tested it and yes my Code automatically generates new VAPID keys for each Environment/Tenant, and writes them to our Database.

        private async Task<VapidDetails> CheckOrGenerateVapidDetails(string vapidSubject, string vapidPublicKey, string vapidPrivateKey, int tenantid)
        {
            if (string.IsNullOrEmpty(vapidSubject))
            {
                return null;
            }

            if (string.IsNullOrEmpty(vapidSubject) ||
                string.IsNullOrEmpty(vapidPublicKey) ||
                string.IsNullOrEmpty(vapidPrivateKey))
            {
                var vapidKeys = VapidHelper.GenerateVapidKeys();
                vapidPublicKey = vapidKeys.PublicKey;
                vapidPrivateKey = vapidKeys.PrivateKey;
                await _tr.UpdateVapidDetailsAsync(tenantid, vapidSubject, vapidPublicKey,vapidPrivateKey);
            }
            return new VapidDetails(vapidSubject, vapidPublicKey, vapidPrivateKey);
        }

This Code runs when no VAPID keys are given/generated on Startup in the current context, inside of my Push Controller.


        public async Task<IActionResult> VapidPublicKey()
        {

            if(_vapidDetails == null)
            {
                _vapidDetails = await CheckOrGenerateVapidDetails(Request.Host.Host, null, null, _tenant.Id);
            }

            return Json(_vapidDetails.PublicKey);
        }

......
        public async Task<IActionResult> Subscribe([FromBody] PushSubscriptionViewModel model)
        {
            if (_vapidDetails == null)
            {
                _vapidDetails = await CheckOrGenerateVapidDetails($"https://{Request.Host}", null, null, _tenant.Id);
            }
     .....
        }
TASimpson commented 4 years ago

@mark-szabo

I too am having a 403 issue with every environment besides my own. I have followed the demo set up almost to a "T". Including the service: https://github.com/MicrosoftEdge/pushnotifications-demo-aspnetcore/blob/master/PushnotificationsDemo/Services/PushService.cs

For my public and private key I saved it as env variable so that everything who pulls latest or when we push it to dev and up. Will have those keys as well.

I to this day do not have any issues receiving the notifications.

But in co-workers and dev environments. I get the same exact exception above. Any help will be more than appreciated! I have been banging my head against the wall.

From certs to appsettings to env variables to keys....I do not see any differences. What am I missing?!

gavrilyuc commented 3 years ago

I have the same trouble. I didn't change the project I just downloaded and ran it.

fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
WebPush.WebPushException: Received unexpected response code: 403
   at WebPush.WebPushClient.HandleResponse(HttpResponseMessage response, PushSubscription subscription)
   at WebPush.WebPushClient.SendNotification(PushSubscription subscription, String payload, Dictionary`2 options)
   at WebPush.WebPushClient.SendNotification(PushSubscription subscription, String payload, VapidDetails vapidDetails)
   at PushnotificationsDemo.Services.PushService.Send(String userId, Notification notification) in /Users/gavrilyuc/Downloads/pushnotifications-demo-aspnetcore-master 2/PushnotificationsDemo/Services/PushService.cs:line 96
   at PushnotificationsDemo.Services.PushService.Send(String userId, Notification notification) in /Users/gavrilyuc/Downloads/pushnotifications-demo-aspnetcore-master 2/PushnotificationsDemo/Services/PushService.cs:line 107
   at PushnotificationsDemo.Controllers.PushController.Send(String userId, Notification notification, Nullable`1 delay) in /Users/gavrilyuc/Downloads/pushnotifications-demo-aspnetcore-master 2/PushnotificationsDemo/Controllers/PushController.cs:line 105
   at lambda_method(Closure , Object )
   at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()
   at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.TaskOfActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
gavrilyuc commented 3 years ago

Can you help me, anybody? @molant @mark-szabo @TASimpson

pouyababaie commented 3 months ago

any updates on this?