SignalR connection failing when calling through an intermittent WebApi Service - asp.net-web-api

I've an angular app, a gateway service(web api) and an asp.net core service(where the SignalR hub is present). I'm trying to connect from the angular app to SignalR hub through the gateway and the request is failing with the below error:
Access to XMLHttpRequest at '(gateway)/signalR/connect/negotiate' from origin '(UI website)' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
//UI code:
this is request I'm posting from angular app.
const connection = new signalR.HubConnectionBuilder()
.withUrl(https://gateway/signalr/connect)
.withAutomaticReconnect()
.build();
//Gateway code:
https://gateway/signalr/connect is a post api in gateway service.
With in the gateway post api, I'm making a connection to signalr hub like below:
https://localhost:19081/(myservice)/SignalR/(myHub)
//SignalR Service:
Also added the below cors policy in my signalr startup:
services.AddCors(options => options.AddPolicy("SignalRPolicy", builder =>
{
builder.AllowAnyHeader()
.AllowCredentials()
.AllowAnyMethod()
.WithOrigins(<allowedorigins>);
}));
app.UseCors("SignalRPolicy");
app.UseAzureSignalR(routes =>
{
routes.MapHub<HubClass>("/<myhub>");
});
If I directly call the SignalR hub from UI - this request is passing and connecting to signalr successfully.
Here both Gateway service and my signalr service are hosted on azure service fabric. The requirement is, all the calls from UI need to go through the gateway.
Please let me know how I can make this work. Thank you.

You must to explicit (withCredentials: false) at hub connection.
const connection = new signalR.HubConnectionBuilder()
.withUrl(https://gateway/signalr/connect,
{ skipNegotiation: false,
withCredentials: false,
transport: signalR.HttpTransportType.WebSockets })
.withAutomaticReconnect()
.build();

Related

CORS Settings for AWS Lambda via API Gateway

Am getting the following error:
Access to fetch at 'https://...' from origin 'https://...' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
p.s. from blazor wasm web api call
Enabling CORS support for Lambda or HTTP non-proxy integrations and AWS service integrations
For a Lambda custom (non-proxy) integration, HTTP custom (non-proxy) integration, or AWS service integration, you can set up the required headers by using API Gateway method response and integration response settings. When you enable CORS by using the AWS Management Console, API Gateway creates an OPTIONS method and attempts to add the Access-Control-Allow-Origin header to your existing method integration responses.
This doesn’t always work, and sometimes you need to manually modify the integration response to properly enable CORS. Usually this just means manually modifying the integration response to return the Access-Control-Allow-Origin header.
exports.handler = async (event) => {
const response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Headers" : "Content-Type",
"Access-Control-Allow-Origin": "https://www.example.com",
"Access-Control-Allow-Methods": "OPTIONS,POST,GET"
},
body: JSON.stringify('Hello from Lambda!'),
};
return response;
};
Have you tried the following?
make sure to set
Access-Control-Allow-Origin
*
Access-Control-Allow-Headers
*
Access-Control-Allow-Methods
*
p.s.
you may need to make the above more restrictive e.g. to your apps domain
also don't forget to clear your browsers cache
https://console.aws.amazon.com/apigateway/main/develop/cors

Serverless WebSocket route responses

I am using serverless to create a WebSocket service, for which I am able to successfully trigger my WebSocket routes locally, using serverless-offline and for the deployed service.
The issue I am having now is responding to those WS events.
I am able to use AWS.ApiGatewayManagementApi.postToConnection to respond to my local WebSocket events, though I cannot seem to get the return value of my handler to actually send a WebSocket event in response, as these serverless-offline docs and these AWS docs suggest.
The serverless.yml route:
ws-custom:
handler: handler.wsCustom
events:
- websocket:
route: custom
routeResponseSelectionExpression: $default
The handler:
module.exports.wsCustom = async (event) => {
const body = JSON.parse(event.body);
console.log('WebSocket `custom` event!', event);
return {
statusCode: 200,
body: JSON.stringify({ message: `Hello, ${body.name}!` }),
};
}
Invoking the function in my browser JavaScript:
ws.send(JSON.stringify({ 'action': 'custom', 'name': 'kevbot' }));
The result is that my serverless-offline logs (or CloudWatch in the case of the deployed project) will create an event with the log successfully, but my client will receive no events in response.
Does anyone know how I can do this with the return value of the handler?
EDIT:
The problem seems to exist within my serverless-offline setup. I will attempt to get it working locally and will create an issue necessary.
An important point to note when using WebSocket APIs and trying to return a response from your integration back to the client, as mentioned in this doc:
For a route that is configured to use AWS_PROXY or LAMBDA_PROXY integration, communication is one-way, and API Gateway will not pass the backend response through to the route response automatically. For example, in the case of LAMBDA_PROXY integration, the body that the Lambda function returns will not be returned to the client. If you want the client to receive integration responses, you must define a route response to make two-way communication possible.
So, if you are using a proxy integration, then you cannot return a response back to the client. You would have to use the AWS.ApiGatewayManagementApi.postToConnection method to communicate any data.
Alternatively, if you are using a non-proxy integration, then you can set up a route response for your integration.

Send Authorization cookie when using socket.io client inside Iframe via WebSocket

I'm trying to create a websocket connection using socket.io client.
My issue starts when my app is running inside an Iframe.
The browser does not send the Authorization cookie which is being set by the server.
There is no CORS issue since the iframe and the server are running on the same domain.
The cookie configurations are: HttpOnly = true, Secure = true, SameSite = Strict.
It does work when the app is running without an iframe.
Example of my code
this.socket = io(`/${namespace}`, {
transports: ['websocket'],
path: '/.../socket.io'
});

ERR_INSECURE_RESPONSE

In my angular2 app I making a HTTPS post request to the API:
this.http.post('https://myhost.com/api/users/sign_in', body, { headers: contentHeaders })
.subscribe(
response => {.....
And I am getting "failed to load resource: net::ERR_INSECURE_RESPONSE"
Everything was fine with HTTP until I switched to HTTPS.
I am using self signed certificate for myhost.com.
In browser I am able to accept the certificate and make a request to the API. Could I resolve this also to make an API request via http.post from angular2 directly?

How to get HTTP request and response from WebSocket connection

Currently, we are using a fairly standard setup with Node.js + Passport + AJAX as the webserver, Backbone on the client, and an app server exposing APIs for the back-end. The client makes AJAX request to Node, which does some housecleaning such as checking the session authentication, then passes the request along to the app server.
We are experimenting with replacing the AJAX portion between the client and Node with WebSockets. That part I have working fine. Previously we were using passport to check if the request was authenticated. With a standard Node route, the request and response is always included so this is a trivial task, but I'm not sure how to get it from the socket.
var server = http.createServer(app).listen(port);
var io = socketio.listen(server);
var namespaced = io.of('/socket/test');
namespaced.on('connection', function (socket) {
console.log('a user connected to /socket/test');
socket.on('fetch', function (args) {
// the client has sent a socket message which will functionally replace an AJAX request
// authenticate session here - how to get the request??
});
});

Resources