Basic authorization fails when using Flurl - authorization

In an api demo, WebClient authenticates correctly when set like this
client.Headers["authorization"] = $"Basic Njk4NzYzNTc6dGVzdHBhc3N3b33JkX0RFTU9QUklWQVRFS0VZMjNHNDQ3NXpYWlEyVUE1eDdN";
Using Flurl.Http 3.0.4, all the following fail with "invalid login or private key"
await url.WithOAuthBearerToken("Njk4NzYzNTc6dGVzdHBhc3N3b3JkX0RFTU9QUklWQVRFS0VZMjNHNDQ3NXpYWlEyVUE1eDdN").GetJsonAsync();
await url.WithOAuthBearerToken("Basic Njk4NzYzNTc6dGVzdHBhc3N3b33JkX0RFTU9QUklWQVRFS0VZMjNHNDQ3NXpYWlEyVUE1eDdN").GetJsonAsync();
await url.WithHeader("authorization", "Njk4NzYzNTc6dGVzdHBhc3N3b33JkX0RFTU9QUklWQVRFS0VZMjNHNDQ3NXpYWlEyVUE1eDdN").GetJsonAsync();
await url.WithHeader("authorization", "Basic Njk4NzYzNTc6dGVzdHBhc3N3b3JkX0RFT3U9QUklWQVRFS0VZMjNHNDQ3NXpYWlEyVUE1eDdN").GetJsonAsync();
How do I implement the authorization demonstrated when using Flurl?

Related

AzureAD, Client confidential app calling webapi with a custom Application ID URI, returns 401

I'm trying to develop an API which can be called from different web apps.
If I call the api with a client confidential app, using the default scope (api://[APIclientId]/.default), everything works.
But If I specify a custom Application ID URI for the API app registration (like: api://myapi.iss.it), and I set the scope to api://myapi.iss.it/.default, I get HTTP401 from the webapp.
This is the method to retrieve the token for the webapp to call the api:
private async Task PrepareAuthenticatedClient()
{
IConfidentialClientApplication app;
string AURY = String.Format(CultureInfo.InvariantCulture, _config["AzureAd:Instance"] + "{0}", _config["AzureAd:TenantId"]);
app = ConfidentialClientApplicationBuilder.Create(_config["AzureAd:ClientId"])
.WithClientSecret(_config["AzureAd:ClientSecret"])
.WithAuthority(new Uri(AURY))
.Build();
var accessToken = await app.AcquireTokenForClient(new string[] { _config["API:scope"] }).ExecuteAsync();
Console.WriteLine("token: " + accessToken.AccessToken);
//var accessToken = await _tokenAcquisition.GetAccessTokenForAppAsync(_TodoListScope);
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.AccessToken);
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
I notice that the Audience is still api://[APIclientId] in the token, even if I set the api:scope to api://myapi.iss.it/.default
Is it correct?
any idea what could be the problem?
I got the solution on the Microsoft Q&A platform.
Basically, I didn't specifiy the Audience in the API application, so by default it was "api://[APIclientId]".
When the API was verifing the token of the app (where the aud was api://myapi.iss.it), the exception "Microsoft.IdentityModel.Tokens.SecurityTokenInvalidAudienceException" was raised, and the API returned 401.
If you have the same problem, and you are using the Microsoft.Indentity.Web library, specifying the Audience in the appsetting.json may be enough.

C# HttpClient failing to make GET requests with Windows Authentication

I have a .NET Core 3.1 Api application with the following configuration of HttpClient. In Startup.cs
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddHttpClient("myapi", c =>
{
c.BaseAddress = new Uri(Configuration["endpoint"]);
c.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(
IISDefaults.AuthenticationScheme, Convert.ToBase64String(
System.Text.Encoding.UTF8.GetBytes($"{Configuration["username"]}:{Configuration["password"]}")));
});
I then try to make an HTTP call like this:
var client = clientFactory.CreateClient(clientName);
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
return await response.Content.ReadAsStringAsync();
however I always get an Unauthorized response when calling an internal api. Under Debug I have Windows authentication and Anonymous authentication both enabled.
With Postman my api calls go through, which verifies that I got the right credentials.
Can you suggest any alterations to make this work?
Instead of c.DefaultRequestHeaders.Authorization =, I'm having config like this
c.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
Credentials = new NetworkCredential("username", "password"),
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
PreAuthenticate = true
});
I guess this will not work as-is in your case, but I hope this can get you on track.

Which is the correct flow to get current user's groups from Microsoft graph?

Hi I am implementing Groups based authorization to my web api. I have client application swagger. Through swagger I am logging in and calling web api. In web api I want to implement groups based authorization through Microsoft graph. When I logging through swagger I will get one token and I am passing to my webapi. If I am not wrong, Now I required one token to call Microsoft graph. So can I use same token to call microsoft graph? I confused my self and implemented client credential flow. Client credential flow will get token for the app(here user signed in token has nothing to do).
public static async Task<GraphServiceClient> GetGraphServiceClient()
{
// Get Access Token and Microsoft Graph Client using access token and microsoft graph v1.0 endpoint
var delegateAuthProvider = await GetAuthProvider();
// Initializing the GraphServiceClient
graphClient = new GraphServiceClient(graphAPIEndpoint, delegateAuthProvider);
return graphClient;
}
private static async Task<IAuthenticationProvider> GetAuthProvider()
{
AuthenticationContext authenticationContext = new AuthenticationContext(authority);
ClientCredential clientCred = new ClientCredential(clientId, clientSecret);
// ADAL includes an in memory cache, so this call will only send a message to the server if the cached token is expired.
AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenAsync(graphResource, clientCred).ConfigureAwait(false);
var token = authenticationResult.AccessToken;
var delegateAuthProvider = new DelegateAuthenticationProvider((requestMessage) =>
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", token.ToString());
return Task.FromResult(0);
});
return delegateAuthProvider;
}
Below code will return all the groups.
GraphServiceClient client = await MicrosoftGraphClient.GetGraphServiceClient();
var groupList = await client.Groups.Request().GetAsync();
but my requirement is to get current signed in users group. So can someone help me which flow I should use and In the above code only Is it possible to get current users group? Can someone help me in understanding these and implement correctly? Any help would be greatly appreciated. Thanks
As we have discussed before, you should call Microsoft Graph API from your webapi app.
So you should not use the same access token to call Microsoft Graph. You should specfy the Microsoft Graph endpoint (https://graph.microsoft.com) as the resource when you request a new access token to Microsoft Graph.
Secondly, client credential flow means app-only permission (without user). So if there is no signed in user, how could we get user's groups?
You should consider using AcquireTokenAsync(String, ClientAssertion, UserAssertion).
After that, using the following code to get the signed in user's groups.
GraphServiceClient client = await MicrosoftGraphClient.GetGraphServiceClient();
var memberOf = await graphClient.Me.MemberOf.Request().GetAsync();

identityserver 4 get current user's access_token

I am having trouble getting my current user's access_token.
Here is my setup:
QuickstartIdentityServer (QIS) in aspnet core, identity and EF storage
API (API) in NodeJs. Validates jwt tokens in header against QIS.
SPA angular app that works great with QIS and API and is out of the scope of this question
In a section of the QuickstartIdentityServer (QIS) site (user details page), I would like to call an API endpoint using an access_token to authenticate the request. I am struggling to retrieve the current user's access_token from my QIS site. Whenever I call HttpContext.GetTokenAsync("access_token") I get a null value. I have seen this section of IdSrv4 documentation: https://identityserver4.readthedocs.io/en/release/quickstarts/5_hybrid_and_api_access.html?highlight=gettokenasync but it seems to apply to an MVC client and not my own identity server.
Anyone could shed some light on how to get my user's access_token ?
Thanks
EDIT
Here is a starting point to try to explain better my issue:
https://github.com/IdentityServer/IdentityServer4.Samples/tree/release/Quickstarts/6_AspNetIdentity/src/IdentityServerWithAspNetIdentity
Starting from this QIS project, I would like to get the logged in user's access token. So for instance, if I edit HomeController to add this call:
public async Task<IActionResult> Index()
{
var accessToken = await HttpContext.GetTokenAsync("access_token");
return View(accessToken);
}
I would then be able to call my NodeJS API with this token in the Auth Header.
Hope this explains better my issue.
So I managed to authenticate myself w/ my API using a dedicated Client using client credentials grant and the following call to get an access_token:
var disco = await DiscoveryClient.GetAsync("http://localhost:5000");
var tokenClient = new TokenClient(disco.TokenEndpoint, clientId, clientSecret);
var tokenResponse = await tokenClient.RequestClientCredentialsAsync(scope);
Then I can add to my request header to API the access_token returned in tokenResponse:
using(var client = new HttpClient()) {
client.SetBearerToken(tokenResponse.AccessToken);
...
// execute request
}
The downside is that I can't "impersonate" the current currently logged on IS on API side.

OAuth 2.0 authentication in RestSharp

I am trying to authenticate RESTful service (sabre REST api) using RESTsharp library but i am not able to authenticate it. I am using my Client id and secret. Please tell me how to authenticate using oAuth 2.0 authenticator.
I have tried this code. ( sabre is using OAuth 2.0 authentication )
public ActionResult Index()
{
var client = new RestClient("https://api.test.sabre.com");
client.Authenticator = new HttpBasicAuthenticator("myclientid", "myclientsecret");
RestRequest request = new RestRequest("/v1/auth/token", Method.POST);
request.AddHeader("Authorization", "Basic " + client);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("grant_type", "client_credentials");
IRestResponse response = client.Execute(request);
var content = response.Content;
ViewBag.R = content;
return View();
}
i got this result
{"error":"invalid_client","error_description":"Credentials are missing or the syntax is not correct"}
please tell what i am doing wrong.
Thanks
Snapshot of Fiddler Comparison of Running code (not with RestSharp) and code using RestSharp is shown
With RestSharp
Seems to me like you are adding the Authorization header twice. The documentation here says
The authenticator’s Authenticate method is the very first thing called
upon calling RestClient.Execute
Looking at the implementation of HttpBasicAuthenticator, the Authenticate method adds the appropriate header to the request.
So remove the following line from your example:
request.AddHeader("Authorization", "Basic " + client);
You need to first obtain access token from Sabre that you can later use while making rest api calls.
The access token POST request looks like this:
POST https://api.test.sabre.com/v2/auth/token
Authorization: Basic ZVc5MWNtTnNhV1Z1ZEdsazplVzkxY21Oc2FXVnVkSE5sWTNKbGRBPT0=
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
where the value of Authorization after Basic is the Base64 encoded string based on your clientId and secret
Refer to Sabre Authentication on how this string is created
So, in order to get the access token you just need to send a POST request with required header and request parameters and you do not need to use the Authenticator