StringContent is sent as empty object to node - c#

I have a C# desktop that needs to use HttpClient to make a post request to my node API. The problem is that the JSON that the node app receives is different than what I am intending. I have tried using the example below and I have read from the StringContent and seen that it contains the values that I expect but it is showing up on the node app as {};
User user = new User
{
Username = username,
Password = password
};
StringContent content = new StringContent(JsonConvert.SerializeObject(user));
HttpResponseMessage response = await client.PostAsJsonAsync("auth", content);
I have also tried similar code but instead of StringContent I used only string like this:
User user = new User
{
Username = username,
Password = password
};
StringContent content = JsonConvert.SerializeObject(user);
HttpResponseMessage response = await client.PostAsJsonAsync("auth", content);
But this gives me an error about Unexpected Token " in JSON at position 0;
Please help me understand how I can send a properly serialized user object. I would prefer doing this without implementing ISerializable if possible. here is my User data class:
namespace Cloud_Calendar
{
class User
{
public string Username { get; set; }
public string Password { get; set; }
}
}
I think that it might be useful to see what my node is doing so here it is:
let failCount = 0;
app.all('/failAuth', (req, res) => {
console.log("failed" + (++failCount));
console.log(req.body);
res.send('failure to authenticate user');
});
app.post('/main', (req, res) => { //this will be removed & replaced with routes for each action
res.send('success');
});
app.post('/auth', passport.authenticate('local', { failureRedirect: '/failAuth' }), (req, res) => {
//TODO: if success parse req.body to search for req.body.action variable and redirect based on value
console.log(`req.body.action: ${req.body.action}`); //this indicates desired action
try{
res.redirect(308, '/main');
}catch(err){
console.error(err);
}
});
req.body is logged as empty... is this because of the redirect?

With PostAsJsonAsync you need to pass the object as is. Internally it will serialize the object, create a StringContent and post that via the HttpClient
So either use PostAsJsonAsync as it was intended
User user = new User
{
Username = username,
Password = password
};
HttpResponseMessage response = await client.PostAsJsonAsync("auth", user);
Or perform the serialization yourself (basically what PostAsJsonAsync does internally)
User user = new User
{
Username = username,
Password = password
};
string json = JsonConvert.SerializeObject(user);
StringContent content = new StringContent(josn, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync("auth", content);

Related

HTTPClient Post Request and get User Token

I have created a function which takes the username, password and the endpoint (url) and returns the token.
Here is the function:
public string GetToken(KiaaaAuthClient authClient)
{
Debug.Log("GetToken function executed");
// HttpClient object
HttpClient client = new HttpClient();
Debug.Log("62");
// Creating values for the request
var values = new Dictionary<string, string>
{
{"username", authClient.userName},
{"password", authClient.password},
};
Debug.Log("70");
// Encoding request in Http form
var data = new FormUrlEncodedContent(values);
Debug.Log("74");
// Response message
HttpResponseMessage responseMessage = client.PostAsync(authClient.endPoint, data).Result;
Debug.Log("78");
// Json string content
var jsonContent = responseMessage.Content.ReadAsStringAsync().Result;
Debug.Log("82");
// Getting a dictrionary from the JSON string
var jsonDict = JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonContent);
Debug.Log("86");
// if 'error' is not present in jr (dictionary)
if (!jsonDict.ContainsKey("error"))
{
authClient.token = jsonDict["access_token"];
return authClient.token;
}
else
{
Debug.Log("Error: failed to acquire token");
return null;
}
It gave the webexception error (name resolution failure). Can anyone give me the reason for this? Moreover, I am very new to this, I am not sure whether it is a correct way to post a request and get the user authentication token. Please guide!

POST Request in xamarin forms

I'm trying authenticate a user on WordPress using a REST API Route configured with POST method. I have already done this with it configured with the GET method but this isn't exactly safe for user authentication. So I need to send a POST request to this endpoint with the email and password I get from the login form. The code I currently have does get to the endpoint which uses the function and returns a string if I put echo "It works". However if I try to echo or return the values of my POST it returns nothing.
Xamarin Code:
var password = Wachtwoord.Text;
var email = Email.Text;
var client = new HttpClient();
var content = new StringContent(
JsonConvert.SerializeObject(new { email = email, password = password }));
var result = await client.PostAsync("https://staging.myopinion.be/wp-json/app-endpoint/auth", content).ConfigureAwait(false);
if (result.IsSuccessStatusCode)
{
var tokenJson = await result.Content.ReadAsStringAsync();
var test = tokenJson;
}
WordPress Functions code:
function authenticate_user(WP_REST_Request $request) {
$login = $_POST;
$email = $_POST['email'];
$password = $login['password'];
echo $email;
}

Getting bad request for missing parameter 'grant_type' even though it's part of my request body

I have tried to get access token for PowerBI API with the following method and proper inputs for clientId, clientSecret, username and password but I get Bad Request saying required parameter 'grant_type' is missing.
public static async Task<string> GetToken()
{ ​
var client = new RestClient();
​
var url = "https://login.microsoftonline.com/common/oauth2/token"
var request = new RestRequest(url, Method.POST, DataFormat.Json);
​
var body = new
{
grant_type = "password",
client_id = "clientId",
client_secret = "clientSecret",
username = "user",
password = "password",
resource = "https://analysis.windows.net/powerbi/api"
};
​
request.AddJsonBody(body);
​
var response = await client.ExecutePostAsync(request);
return response.Content;
}
Something wrong with by JSON body or something completely different?
Your request body needs to be form url encoded - not json
If you're using C# I'd recommend using the Identity model library to reduce mistakes.
Here is some sample code

Is there a way to delete Azure Function from my Function App using C#?

I am trying to delete an Azure function from my Function App through C#.
But while deleting it programmatically, the function is not seen on the User Interface, but when I check it through Advanced tools (Kudu), I can still see my Azure function.
So basically while deleting the Azure function, what I do is, I delete it's function.json, and by doing so the Azure function isn't visible in Functions App list (see image below)
But when I go to Advanced Kudu to check whether it has been deleted, I can still see it, but without the function.json file. I had done this before (around 6 months back) and back then it was working properly. I don't know if I am doing it wrong or has anything changed.
Any help with the code would be appreciated.
Thanks
Edit:
The details that I have with me is the Function App's username, password, url, name (https://my-function-app.scm.azurewebsites.net/api/vfs/site/wwwroot), and azure function's name.
A little sample code of what I did which worked 6 months back
private WebClient _webClient = new WebClient
{
Headers = { ["ContentType"] = "application/json" },
Credentials = new NetworkCredential(username, password),
BaseAddress = functionsSiteRoot,
};
var functionJson =
JsonConvert.DeserializeObject<FunctionSettings>(_webClient.DownloadString("MyFunctionName/function.json"));
_webClient.Headers["If-Match"] = "*";
_webClient.UploadString("MyFunctionName/function.json", "DELETE", JsonConvert.SerializeObject(functionJson));
You could use REST API to perform this operation.
https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{name}/functions/{functionName}?api-version=2016-08-01
Method: DELETE
Code Snippet:
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Delete, string.Format("https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{name}/functions/{functionName}?api-version=2016-08-01", "Pass All Param In {}")));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", results.access_token);
HttpResponseMessage response = await _client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
dynamic objApiResponse = JsonConvert.DeserializeObject<dynamic>(await response.Content.ReadAsStringAsync());
}
else
{
return req.CreateResponse(HttpStatusCode.OK, "Sorry Invalid Request");
}
For details please have a look on official docs
Note: For token request your resource/Scope should be https://management.azure.com. Pass your token while send request.
Update:
You can request for token using client_credentials authentication flow. Try below format:
Azure Portal Credentials For App Id and Tenant Id:
Application Secret from Portal:
Token Endpoint Or URL:
https://login.microsoftonline.com/YourTenantName.onmicrosoft.com/oauth2/token
Request Param:
grant_type:client_credentials
client_id:b603c7be_Your_App_ID_e6921e61f925
client_secret:Vxf1Sl_Your_App_Secret_2XDSeZ8wL/Yp8ns4sc=
resource:https://graph.microsoft.com
PostMan Sample:
Token On Response:
Code Snippet For Token:
//Token Request End Point
string tokenUrl = $"https://login.microsoftonline.com/YourTenant/oauth2/token";
var tokenRequest = new HttpRequestMessage(HttpMethod.Post, tokenUrl);
//I am Using client_credentials as It is mostly recomended
tokenRequest.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["grant_type"] = "client_credentials",
["client_id"] = "20e08e95-_Your_App_ID_e9c711b0d19e",
["client_secret"] = "+trl[ZFl7l_Your_App_Secret__ghon9",
["resource"] = "https://management.azure.com/"
});
dynamic json;
AccessTokenClass results = new AccessTokenClass();
HttpClient client = new HttpClient();
var tokenResponse = await client.SendAsync(tokenRequest);
json = await tokenResponse.Content.ReadAsStringAsync();
results = JsonConvert.DeserializeObject<AccessTokenClass>(json);
//New Block For Accessing Data from API
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Delete, string.Format("https://management.azure.com/subscriptions/YOurSubscription/resourceGroups/YourResourceGroup/providers/Microsoft.Web/sites/DeleteTestFuncAppName/functions/DeleteFunctionNameThatYouWantToDelete?api-version=2016-08-01"));
//Passing Token For this Request
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", results.access_token);
HttpResponseMessage response = await client.SendAsync(request);
//Read Server Response
dynamic objServerResponse = JsonConvert.DeserializeObject<dynamic>(await response.Content.ReadAsStringAsync());
Class I Have Used:
public class AccessTokenClass
{
public string token_type { get; set; }
public string expires_in { get; set; }
public string resource { get; set; }
public string scope { get; set; }
public string access_token { get; set; }
public string refresh_token { get; set; }
}
Point To Remember:
If you got this error
InvalidAuthenticationToken: The received access token is not valid: at
least one of the claims 'puid' or 'altsecid' or 'oid' should be
present. If you are accessing as application please make sure service
principal is properly created in the tenant
You have to assign role to your application like below:

Get user name and email using Microsoft.Identity.Client

I am using this package https://www.nuget.org/packages/Microsoft.Identity.Client
to authenticate a user, auth is working fine, problem is, I was thinking to use the token that I get after login to get the user name and email (as I need not only access to the inbox, contacts, and calendar; but also link the user to a rol using an email).
The problem is, when I get the token, I get a long string as userId (I guess encrypted). Is there any way I can use this package to get the email?
This is the section where I get the token back
public SessionTokenCache(string userId, HttpContextBase httpContext)
{
this.userId = userId;
cacheId = userId + "_TokenCache";
this.httpContext = httpContext;
BeforeAccess = BeforeAccessNotification;
AfterAccess = AfterAccessNotification;
Load();
}
This is the tutorial I followed
https://dev.outlook.com/restapi/tutorial/dotnet
Once you have a token, maybe you can use the Graph API to get details for the logged on user? The result is Json which can be used to extract the bits you want.
public static async Task<string> GetUserData(string token)
{
//get data from API
HttpClient client = new HttpClient();
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me");
message.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", token);
HttpResponseMessage response = await client.SendAsync(message);
string responseString = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
return responseString;
else
return null;
}

Categories