Authentication; accessing web service from .net core (5.0) - c#

I'm trying to access a jira server from .net (core 5.0 on Windows) desktop application.
If I use curl (WSL) like so:
curl -u userid:pwd -X GET -H "Content-Type: application/json" https://jira.jira.com/rest/agile/1.0/board
JSON is returned.
I tried to something similar in .NET:
var wc = new WebClient();
wc.Credentials = new NetworkCredential("userid", "pwd");
wc.Headers.Add("Content-Type", "application/json");
var reply = wc.DownloadString("https://jira.jira.com/rest/agile/1.0/board");
and the download call throws a 401.
Interestingly, if I take the "Authorization" header generated by curl and add it to the headers (wc.Headers.Add("Authorization", "Basic xxxxxxxxxxxx=");). The call works and returns JSON.
Two questions.
What does the 'Credentials' property do if it's not adding the header?
Is there a simply way to get the domain id info and pass on appropriate information so my application doesn't deal with user/pwd at all?
If you suggest MSAL for the second question please provide a simple example that doesn't require registering a client id (if possible).

Related

Google Identity Toolkit API in C#

Some Background Information
I am building a game in Unity, using C#. Since I am using Firebase and the ready-made Unity Firebase SDK won't work in my case1, I have resorted to interfacing with Firebase's REST API through C#'s HttpClient class (which comes with System.Net.Http).
I am currently struggling with the Firebase Authentication APIs. For those unfamiliar with OAuth APIs, when I call the Sign Up or Sign In endpoints, I get both an ID Token and a Refresh Token. ID Tokens expire; refresh tokens do not. When the ID Token expires, I must call another endpoint, called the Token Exchange, to get a new ID token using my refresh token.
1 There is a rumored Google Identity Toolkit C# library, but the first result returned by that search I found it by leads to a 404 error instead of documentation. 😢
What Does Work
Following the Firebase guides and the underlying Identity Toolkit guides, I have been successful so far interfacing the token exchange endpoint with a cURL command from bash:
curl 'https://securetoken.googleapis.com/v1/token?key=[MY FIREBASE API KEY]' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data 'grant_type=refresh_token&refresh_token=[MY REFRESH TOKEN]'
of course, I replace [MY FIREBASE API KEY] with my Firebase Web API key, and [MY REFRESH TOKEN] with the refresh token returned from the sign in/sign up endpoints.
However, despite my many attempts, I have not been able to replicate this cURL command in C#!
My Failed Attempts
1.
Here's my original code that didn't work.
public async Task<bool> ExchangeToken()
{
FormUrlEncodedContent body = new FormUrlEncodedContent(new Dictionary<string, string>() {
{"grant_type", "refresh_token" },
{"refresh_token", Uri.EscapeDataString(user.refreshToken) }
});
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, "https://securetoken.googleapis.com/v1/token?key=" + apiKey);
message.Content = body;
message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
HttpResponseMessage res = await client.SendAsync(message);
}
Unfortunately, I get this 401 (Unauthorized) error response:
{
"error": {
"code": 401,
"message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED"
}
}
This is quite strange, considering that I get a 2XX (OK) response from what should be an equivalent cURL command...
2.
Thanks to a very nice website I just discovered, I was able to "convert" my cURL command into C# code. However, this did not work. I got the exact same error as attempt #1.
public async Task<bool> ExchangeToken()
{
using (var request = new HttpRequestMessage(new HttpMethod("POST"), "https://securetoken.googleapis.com/v1/token?key=[I WOULD INSERT MY KEY HERE]"))
{
request.Content = new StringContent("grant_type=refresh_token&refresh_token=[INSERT REFRESH TOKEN HERE]", Encoding.UTF8, "application/x-www-form-urlencoded");
var res = await client.SendAsync(request);
}
}
Possible Leads
All of my other requests to all of the other endpoints work. There are two notable differences: 1) the API is technically not Firebase's, but Google Identity Toolkit's. 2) This is the only endpoint that I'm using that uses a Content-Type header of application/x-www-form-urlencoded instead of application/json.
My Question / TL;DR
How do I interface with the Google Identity Toolkit API's Token Exchange endpoint using C#?
(Though I'm currently using the HttpClient class, I'm totally open to other solutions! They just have to be compatible with Unity3D.)
Thanks in advance!
Google wants you to be using Firebase for auth. While Firebase does not have a .NET client SDK shipped by Google, there are other options.
If you don't use Firebase and perform the requisite tasks with oAuth/OpenID Connect endpoints yourself, that works too. There is a Google .NET SDK that helps you with this...a little bit . The SDK lists Google APIs that are "supported" by the SDK; Google Cloud Identity v1 and v1beta APIs are both on the list. So you could call Google Cloud Identity endpoints via this .NET SDK. You do have to understand the implications of various auth flows whereas in Firebase much of that machinery is abstracted away from you as the app developer.
After playing around with the code a little more, I remembered that I was setting default authorization on my HttpClient:
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", idToken);
This was included for all of the other API calls, as they require authentication with the ID Token. However, this seemed to be confusing the token exchange endpoint; it must 1) look for an authorization header, then 2) use the refresh token supplied in the message contents.
How to fix this issue
Instead of setting the default header on your HttpClient (Which is supposed to be reused for all of your HTTP requests), do the following:
var req = new HttpRequestMessage(/* HttpMethod enum value, endpoint URL/IP */);
req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", user.idToken); //Set the authorization per-request, not globally
var res = await client.SendAsync(req);
Then just simply call the Token Exchange endpoint!
From the Firebase REST API Documentation:
You can refresh a Firebase ID token by issuing an HTTP POST request to the securetoken.googleapis.com endpoint.
https://securetoken.googleapis.com/v1/token?key=[API_KEY]
Just provide a refresh_token parameter in the body (along with the mandatory grant_type with value refresh_token). DO NOT provide an authorization header.
Hope this helps anyone with the same problem!
As an alternative, you can also use https://github.com/google/apis-client-generator to generate the c# client from the discovery docs. I had some naming conflicts when I generated mine, but after resolving those it works.

How could I call Azure Maps API in C# with authorisation and client id?

I am trying to use Azure Maps API to search POIs around a point using its coordinates, and I do not know how to call the API by adding the Authorization and client-id.
This is the request preview I get when I try the API on the Microsoft documentation website.
GET https://atlas.microsoft.com/search/poi/json?api-version=1.0&query=university&lat=10.8232&lon=2.98234&limit=1
Authorization: Bearer eyJ0eXAiOiJKV1……
X-ms-client-id: SUXrtewLVItIG3X5…..
There is an open source project that provides a .NET client for the Azure Maps REST services. There is a NuGet package too. You can find it here: https://github.com/perfahlen/AzureMapsRestServices The Azure Maps plans on also providing an official .NET client for the rest services later this year.
You could use RestSharp. The authorization and client-id are added as header:
using RestSharp;
string url = $"https://atlas.microsoft.com/search/poi/json?api-version=1.0&query=university&lat=10.8232&lon=2.98234&limit=1";
var client = new RestClient(url);
var request = new RestRequest(Method.GET);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("Authorization", “Bearer eyJ0eXAiOiJKV1……”);
request.AddHeader("X-ms-client-id", “SUXrtewLVItIG3X5…..”);
IRestResponse response = client.Execute(request);
if (response.IsSuccessful)
{
string content = response.Content;
}
Don't forget to start by installing the RestSharp NuGet package.

How to authenticate Google Cloud Vision via HTTP Request

I am trying to use Google Cloud Vision via a rest http request using c#. As described here, I tried to authenticate with the api key as a parameter:
string uri = "https://vision.googleapis.com/v1/images:annotate?key=" + API_KEY;
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri);
[...]
response = await client.SendAsync(request);
However, I always get a 403 PERMISSION DENIED Code:
Cloud Vision API has not been used in project XXXXX before or it is
disabled. Enable it by visiting
https://console.developers.google.com/apis/api/vision.googleapis.com/overview?project=XXXXXXX
then retry. If you enabled this API recently, wait a few minutes for
the action to propagate to our systems and retry.
Of course I checked, The API is activated, enabled and there are no API restrictions:
Since there seemed to exist some problems with that authentication method, especially with cloud vision, I tried authentication via an access token of a service account that I created. I gave the service account full access just to be sure that there is no issue with the rights of the service account:
string uri = "https://vision.googleapis.com/v1/images:annotate";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri);
request.Headers.Add("Authorization", "Bearer " + ACCESS_TOKEN);
response = await client.SendAsync(request);
Still, same error message. Same goes with curl:
curl -k -X POST -H "Content-Type:application/json"
-d "#{REQUEST_AS_JSON_OR_PATH_TO_JSON-FILE}"
https://vision.googleapis.com/v1/images:annotate?key={API_KEY}
What am I missing out?
Turned out it is NOT sufficient to activate an API key (even when its without any restrictions), but one needs to actively go to the Google console menu -> APIs and Services -> Library -> Search for "Cloud Vision" -> klick on the Cloud vision API and activate it. It takes a couple of minutes. The status of this is not shown in your dashboard.
Then, you can simply authenticate with the api key as URL parameter.

How to securely get access token from Marketo

Marketo Rest API exposes a GET call to oauth/token uri, which exposes clientId and clientSecret parameters to all internet hops between the 2 networks. Am I missing something or is there a way we can securely get an access token?
Marketo also has a POST method for this endpoint where you can send the clientId and clientSecret as x-www-form-urlencoded POST parameters
curl -X POST -H "Cache-Control: no-cache" -H "Content-Type: application/x-www-form-urlencoded" -d 'client_id=MY_CLIENT_ID&client_secret=MY_CLIENT_SECRET&grant_type=client_credentials' "https://MY_MARKETO_URL/identity/oauth/token"
I actually got my facts wrong, basically this get call is https, and query parameters will be sent encrypted over the wire once it establishes a secure connection to the server. Only caveat I found is that a server admin can read the credentials in clear text if browsed server file system which is a low risk.

Windows Authentication in ASP .Net for WebApi

I have written a simple ASP.Net WebAPI that download a file from an on-prem tfs server using a rest call. The issue is when I connect to this site from my user account(corp domain), and set the credentials in webRequest to CredentialsCache.DefaultCredentials, it works fine since I am a vlid user on the tfs project.
Now someone else in my team wishes to use the same webAPI and when they hit the same url, I could see that its my credentials being used again to download the file.
I suspect this is because of using CredentialsCache.DefaultCredentials in my controller code, but I am not able to find a way using which I should be able to use the client's identity to be used for the download request.
My question is , is there a way to extract the windows identity or network credentials of the remote user(on the same domain) which I can use for Authentication. I am sorry if this is a DUP but I could not find a targetted answer to my question yet. Sample code is pasted below.
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Credentials = CredentialCache.DefaultNetworkCredentials;
try
{
var webResponse = request.GetResponse();
var webStream = webResponse.GetResponseStream();
if (webStream != null)
{
var objReader = new StreamReader(webStream);
return objReader.ReadToEnd()
}
}
I dont know if I understand you correctly but I think impersonation is what you're looking for:
http://msdn.microsoft.com/en-us/library/xh507fc5.ASPX

Categories

Resources