How to pass Custom Header from React JS client to SignalR hub? - signalr

I am setting up a new SignalR react app ("#aspnet/signalr") with Dot Net Core 2.0. I want to send custom headers to SignalR hub "negotiate" request (like request.headers["MyHeader"] = "Header").
I am able to connect to hub and get data back to react app. I have tried setting custom header by trying to overwrite httpClient in options passed to "withUrl".
With the code provided here I am getting error: "Error: Failed to complete negotiation with the server: Error: Unexpected status code returned from negotiate undefined"
It connects when httpClient is removed from options.
import { HubConnectionBuilder } from '#aspnet/signalr';
const options = {
accessTokenFactory: () => {
return "jwt token";
},
httpClient: {
post: (url, httpOptions) => {
httpOptions.headers = {
...httpOptions.headers,
MyHeader: "NewHeader"
};
httpOptions.method = "POST";
httpOptions.url = url;
return httpOptions;
}
}
};
const connection = new HubConnectionBuilder()
.withUrl("https://localhost:5001/chatHub", options)
.build();
connection.start().catch(function(err) {
console.log("Error on Start : ", err);
});
The way I see header as "Authorize": "jwt token", I expect to see another header in "https://localhost:5001/chatHub/negotiate" request as "MyHeader": "NewHeader"

Found answer to this.
httpClient.post overwrites the response of default SignalR httpClient.post.
Below update to httpClient worked.
httpClient: {
post: (url, httpOptions) => {
const headers = {
...httpOptions.headers,
MyHeader: "MyHeader"
};
return axios.post(url, {}, { headers }).then(response => {
return (newResponse = {
statusCode: response.status,
statusText: response.statusText,
content: JSON.stringify(response.data)
});
});
}
}
SignalR "negotiate" expects response in this form.
{
statusCode: 200,
statusText: "ok",
content: "<string response>"
}

Related

SignalR connection does not work in angular

I had an old backend structure. When i research, i always encounter with signalr with .net core. But i had .net structure and there is no code in the Internet. Could anyone help me to solve this problem?
Here is my code:
private hubConnection: HubConnection;
private hubUrl: string = `${environment.hubUrl}`;
constructor() { }
ngOnInit(): void {
this.startHubConnection();
}
// eslint-disable-next-line #typescript-eslint/explicit-function-return-type
startHubConnection() {
// #ts-ignore
this.hubConnection = new HubConnectionBuilder()
.withUrl(this.hubUrl,
// {
// // eslint-disable-next-line #typescript-eslint/naming-convention
// // httpClient : { 'Access-Control-Allow-Origin': '*'},
// headers: {
// // eslint-disable-next-line #typescript-eslint/naming-convention
// 'Access-Control-Allow-Origin': '*',
// },
// }
)
// .withAutomaticReconnect()
.configureLogging(LogLevel.Information)
.build();
this.hubConnection.start().then().catch(err => console.log('hata yeri '+err));
this.hubConnection.on('SicaklikHub', (response: any) => {
const resp = JSON.parse(response);
console.log(resp);
});
}
This is my output right now:
Access to fetch at 'http://domain:port/signalr/hubs/negotiate?negotiateVersion=1' from origin 'http://localhost:4200' 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.

Send a request to Asp.net WebService using Angular

I executed a WebService using Postman and it's executed correctly. And now i want to send a request to the WebService using Angular
Here is the Asp.net Web Service
This is the code for my WebService
public class Temperature : System.Web.Services.WebService
{
[WebMethod]
public double Farenheit(double celsius)
{
return (celsius * 9) / 5 + 32;
}
[WebMethod]
public double Celsius(double fahrenheit)
{
return (fahrenheit - 32) * 5 / 9;
}
}
And this is the screenshot on how i send a request using PostMan and it's working as expected
Screenshot for Calling the WebService using Postman
Here is the code for the Angular
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'text/xml',
})
};
this.http.post('https://localhost:44389/Temperature.asmx/Celsius', '50', httpOptions)
.subscribe(res => {
console.log('Data: ' + res);
})
And this is the error I'm receiving
Error
"System.InvalidOperationException: Request format is invalid: text/xml.
at System.Web.Services.Protocols.HttpServerProtocol.ReadParameters()
at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()
"
Message
Http failure response for https://localhost:44389/Temperature.asmx/Celsius: 500 OK
Name
"HttpErrorResponse"
Change your 'Content-Type': 'text/xml' to 'Content-Type': 'application/json'
try this :
import { HttpHeaders } from '#angular/common/http';
setHttpHeader() {
const headers = new HttpHeaders().set('Accept', 'application/json').set('Content-Type', 'application/json');
let options = { headers: headers };
return options;
}
this.http.post('https://localhost:44389/Temperature.asmx/Celsius', '50', this.setHttpHeader())
.subscribe(res => {
console.log('Data: ' + res);
})

Meteor HTTP.POST call on same machine (for testing)

I have created a server side route (using iron-router). Code is as follows :
Router.route( "/apiCall/:username", function(){
var id = this.params.username;
},{ where: "server" } )
.post( function(req, res) {
// If a POST request is made, create the user's profile.
//check for legit request
console.log('post detected')
var userId = Meteor.users.findOne({username : id})._id;
})
.delete( function() {
// If a DELETE request is made, delete the user's profile.
});
This app is running on port 3000 on my local. Now I have created another dummy app running on port 5000. Frrom the dummy app, I am firing a http.post request and then listening it on the app on 3000 port. I fire the http.post request via dummy app using the below code :
apiTest : function(){
console.log('apiTest called')
HTTP.post("http://192.168.1.5:3000/apiCall/testUser", {
data: [
{
"name" : "test"
}
]
}, function (err, res) {
if(!err)
console.log("succesfully posted"); // 4
else
console.log('err',err)
});
return true;
}
But I get the following error on the callback :
err { [Error: socket hang up] code: 'ECONNRESET' }
Not able to figure out whats the problem here.
The server side route is successfully called, but the .post() method is not being entered.
Using meteor version 1.6
192.168.1.5 is my ip addr
Okay so if I use Router.map function, the issue is resolved.
Router.map(function () {
this.route("apiRoute", {path: "/apiCall/:username",
where: "server",
action: function(){
// console.log('------------------------------');
// console.log('apiRoute');
// console.log((this.params));
// console.log(this.request.body);
var id = this.params.username;
this.response.writeHead(200, {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
});
if (this.request.method == 'POST') {
// console.log('POST');
var user = Meteor.users.findOne({username : id});
// console.log(user)
if(!user){
return 'no user found'
}
else{
var userId = user._id;
}
}
});
});
It looks like the content type is not set the application/json. So you should do that...
Setting the "Content-Type" header in HTTP.call on client side in Meteor

invalid_grant Google OAuth

I am trying to authentiate through Google's OAuth, but I'm having problems establishing a connection to their API
My client code:
'click #addChannel': function (event) {
event.preventDefault();
var userId = Meteor.userId();
var options = {
requestPermissions: [
'https://www.googleapis.com/auth/youtube',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/youtube.force-ssl',
'https://www.googleapis.com/auth/youtube.readonly',
'https://www.googleapis.com/auth/youtube.upload',
'https://www.googleapis.com/auth/youtubepartner',
'https://www.googleapis.com/auth/youtubepartner-channel-audit',
],
requestOfflineToken: true
};
Google.requestCredential(options, function(token) {
Meteor.call('userAddOauthCredentials', userId, token, function(error, result) {
if (error) {
throw error;
}
console.log(result);
});
});
My server code:
userAddOauthCredentials: function(userId, token) {
check(userId, String);
check(token, String);
var config = ServiceConfiguration.configurations.findOne({service: 'google'});
if (!config) {
throw new ServiceConfiguration.ConfigError();
}
console.log(token, config);
var endpoint = 'https://accounts.google.com/o/oauth2/token';
var params = {
code: token,
client_id: config.clientId,
client_secret: OAuth.openSecret(config.secret),
redirect_uri: OAuth._redirectUri('google', config),
grant_type: 'authorization_code',
};
try { <------------------------------------------------------ this fails
response = HTTP.post(endpoint, { params: params });
} catch (err) {
throw _.extend(new Error("(first) Failed to complete OAuth handshake with Google. " + err.message),
{response: err.response});
}
if (response.data.error) { // if the http response was a json object with an error attribute
throw new Error("(second) Failed to complete OAuth handshake with Google. " + response.data);
} else {
return {
accessToken: response.data.access_token,
refreshToken: response.data.refresh_token,
expiresIn: response.data.expires_in,
idToken: response.data.id_token
};
}
The above throws a [400] { "error" : "invalid_grant" } error.
Most of the above code I got from how the meteor accounts-google packages logs in a user (which works fine in my application). Link to that:
https://github.com/meteor/meteor/blob/87e3c6499d5eacce62f10faefe9ce49c77bb03ee/packages/google/google_server.js
Any advice on how to proceed from here?
Much appreciated
UPDATE1:
I get these warnings in my log
W20150318-09:11:42.532(1) (oauth_server.js:71) Unable to base64 decode state from OAuth query: undefined
W20150318-09:11:42.532(1) (oauth_server.js:71) Unable to base64 decode state from OAuth query: undefined
W20150318-09:11:42.533(1) (oauth_server.js:71) Unable to base64 decode state from OAuth query: undefined
W20150318-09:11:42.534(1) (oauth_server.js:398) Error in OAuth Server: Match error: Expected string, got undefined
You have to parse your var params to application/x-www-form-urlencoded. Please find the below code to parse as i done in php
$fields_string="";
foreach($params as $key=>$value)
{
$fields_string .= $key.'='.$value.'&';
}
rtrim($fields_string, '&');
Now the $filed_string will contained the parse of params array.

Meteor.js and Custom OpenId Connect server

How to do authentication via custom token server in Meteor.js?
Is there any package like accounts-google for custom token server which handles authentication by just taking token endpoints, client id, secrete, and scope as configuration parameter.
I don't know of a generic oauth package. But it shouldn't be too difficult to write a package for your particular server, as there are a number of examples to look at.
Using accounts-github as an example, here's the code for making the connection on the client. Note the endpoint URL, client id, scope, etc. This will handle the popup for you, but you'll probably want to include custom CSS:
var loginUrl =
'https://github.com/login/oauth/authorize' +
'?client_id=' + config.clientId +
'&scope=' + flatScope +
'&redirect_uri=' + OAuth._redirectUri('github', config) +
'&state=' + OAuth._stateParam(loginStyle, credentialToken);
OAuth.launchLogin({
loginService: "github",
loginStyle: loginStyle,
loginUrl: loginUrl,
credentialRequestCompleteCallback: credentialRequestCompleteCallback,
credentialToken: credentialToken,
popupOptions: {width: 900, height: 450}
});
And here's a snippet from the server side, completing the process to get an access token:
var getAccessToken = function (query) {
var config = ServiceConfiguration.configurations.findOne({service: 'github'});
if (!config)
throw new ServiceConfiguration.ConfigError();
var response;
try {
response = HTTP.post(
"https://github.com/login/oauth/access_token", {
headers: {
Accept: 'application/json',
"User-Agent": userAgent
},
params: {
code: query.code,
client_id: config.clientId,
client_secret: OAuth.openSecret(config.secret),
redirect_uri: OAuth._redirectUri('github', config),
state: query.state
}
});
} catch (err) {
throw _.extend(new Error("Failed to complete OAuth handshake with Github. " + err.message),
{response: err.response});
}
if (response.data.error) { // if the http response was a json object with an error attribute
throw new Error("Failed to complete OAuth handshake with GitHub. " + response.data.error);
} else {
return response.data.access_token;
}
};
And utilizing the token to get the user identity:
var getIdentity = function (accessToken) {
try {
return HTTP.get(
"https://api.github.com/user", {
headers: {"User-Agent": userAgent}, // http://developer.github.com/v3/#user-agent-required
params: {access_token: accessToken}
}).data;
} catch (err) {
throw _.extend(new Error("Failed to fetch identity from Github. " + err.message),
{response: err.response});
}
};
The github and the accounts-github packages should be very helpful as references.

Resources