0

I have a PowerShell script that I want to rewrite in C# (initially I wanted to call the PowerShell script from C#, but here it turned out that rewriting it is propably easier and more elegant).

So this is the PowerShell code I need to port to C#:

$uri = "$BaseUri/auth/token"    
$bodyJson = ConvertTo-Json @{token = $ApiToken} -Compress
$response = Invoke-RestMethod `
           -Uri $uri `
           -Method Post `
           -ContentType "application/json" `
           -Body $bodyJson
$jwtToken = $response.token

#jwtToken is then used to authenticate a GET request:
$response = Invoke-RestMethod `
           -Uri $uri `
           -Method Get `
           -ContentType "application/json" `
           -Authentication Bearer `
           -Token $jwtToken `
           -AllowUnencryptedAuthentication 

This is the C# equivalent I came up with:

//this is only called once
//ApiToken only has a field called "token", the class only exists for the JSON parser to work
ApiToken apiToken = new ApiToken();
client.BaseAddress = new Uri(baseUri);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("token", apiToken.Token);

//this is called every time
Task <HttpResponseMessage> postTask = client.PostAsJsonAsync("auth/token", apiToken);   
HttpResponseMessage response = await postTask;
jwt = response.???

Multiple problems here:

  1. I am new to PowerShell and HttpRequesting and I didn't write the script, so I don't fully understand every little detail here
  2. I don't know how to retrieve the JWT returned by the API, as I can't use response.token in C# (why does that even work in PowerShell? Why does response have a field called token?)
  3. The C# code returns Error 401 (Unauthorized), while the PowerShell works fine with the same token. My theory is that this happens because I think I don't send the token correctly. (I'm not sure if my C# message matches the PowerShell ConvertTo-Json @{token = $ApiToken} -Compress) I feel like I didn't really find the proper equivalent for the -Token parameter that Invoke-RestMethod has.
Finni
  • 429
  • 5
  • 17

1 Answers1

0

1) What precisely do you not understand?

2) It works in Powershell because Invoke-RestMethod de-serializes the response and the response contains a field named 'token'. The C# program however wants to know the data structure at compile time. So unless you define it, your program doesn't know about it.

3) If you are doing OAuth, you should be setting "Bearer" in AuthenticationHeaderValue

client.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("Bearer", apiToken.Token);

About the request itself: I can not comment on client.PostAsJson() as I cannot find recent information on the HttpClientExtensions class and my dev environment does not import it automatically either.

However, here is how I did my last webrequest:

var apiToken = new ApiToken()
{
    Token = "mysecret",
};

HttpResponseMessage response = Task<HttpResponseMessage>.Run(async () =>
{
    return await client.PostAsync(
        requestUri: uriEndpoint,
        content: new StringContent(
            content: JsonConvert.SerializeObject(apiToken),
            encoding: Encoding.UTF8,
            mediaType: "application/json"))
    .ConfigureAwait(true);
}).Result;

string fullResponse = await response.Content.ReadAsStringAsync().ConfigureAwait(true);
ApiToken apiResponse = JsonConvert.DeserializeObject<ApiToken>(fullResponse);

Please note that JsonConvert comes from Newtonsoft.Json

0x492559F64E
  • 124
  • 1
  • 13
  • 1) Mainly point 2) gave me an irritating feeling, thanks for clarifying that, it already helped me a lot understanding the code... I added the second REST call in PowerShell which I forgot earlier on. It uses `-Token $jwtToken`, the equivalent for that is `client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken);`, did I get that right? (apiToken.Token is not jwtToken in my case, apiToken is only used to get the jwtToken, after that, I only use jwtToken for the following calls) – Finni Nov 21 '19 at 12:21
  • @Finni if jwtToken is a valid authentication token (of type string), this should work. – 0x492559F64E Nov 21 '19 at 12:27
  • @Finni and to make the GET request you use https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.getasync?view=netframework-4.8 instead of PostAsync – 0x492559F64E Nov 21 '19 at 12:34