I'm using HttpClient to call some REST API with authentication like this:
_networkCredential = new NetworkCredential(username, apiKey);
_httpClientHandler = new HttpClientHandler { Credentials = _networkCredential };
_httpClient = new HttpClient(_httpClientHandler);
This works nicely, but as defined in RFC2617 this will send every request without AUTH header, gets back a 401 and then sends the request a second time with AUTH header.
I'd like to get rid of the extra call without AUTH header to achieve better throughput. For BASIC AUTH I found the following example to manually add the BASIC AUTH header to every call:
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{username}:{apiKey}")));
But my service insists on DIGEST AUTH. How can I achieve this in DIGEST AUTH?
I'd guess I'd have to call the service once and cache the AUTH HEADER for subsequent calls. But if the nonce changes I'd need to refresh the AUTH HEADER? How could this be solved?
Related
I'm trying to setup a web api using ASP.Net Core 6 so that users can hit my end points and then I do some work in D365 behind the scenes using a privileged account. I'm using a typed HTTP Client, but I'm not sure how to plugin the bearer authentication so that all the requests from this client have the correct Authorization header attached.
Program.cs
builder.Services.AddHttpClient<D365Service>();
D365Service.cs
private readonly HttpClient httpClient;
public D365Service(HttpClient httpClient)
{
this.httpClient = httpClient;
this.httpClient.DefaultRequestHeaders.Add("Accept", "*/*");
this.httpClient.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, br");
// a whole bunch of other headers
// Is this where I can add in the bearer Authorization header? How do I generate that token?
}
Any help is appreciated. Thanks.
To add the token to your httpclinet
you should use the following code
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer",accessToken);
How do I generate that token
as #DiplomacyNotWar explained in his comment you should be able to generate that token by following the instructions of the service you are connecting to
Some services will share user name and password ( app Id & secret Key ) and you could use this to set your basic Authentication then you will be able to call your token end point that return the access token that you will be able to use it with your httpclinet
Regards,
I know 2 ways to add token to HttpClient. But I don't know what's the difference between them
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + #YourToken);
And
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", #YourToken);
they work well. but I think they will have something different. if you know, please show me
I am facing an issue with missing Authorization header with Bearer token in the HTTP request from the client application to REST web service via Azure Active Directory Application Proxy.
The web service is hosted in on-premises and client application is consuming from internet using Azure AD application proxy URL and the request is authenticated against ADFS. The authentication header is added upon sending request to Azure AD application proxy URL and I guess it was removed by the proxy connector.
Please find the request content below and help. How can I include Authenticator header in the original request to Application proxy?
GET /TimelogSvc/rest/Timelog/GetTimeLog?EmailId=John#BizNext.com.sg&Fromdate=2019-04-21&Todate=2019-04-27 HTTP/1.1
Connection: Keep-Alive
Host: agileuat.BizNext.com.sg
X-Forwarded-For: 203.126.130.140
X-MS-Proxy: AzureAD-Application-Proxy
OS-Host: agileuat.BizNext.com.sg
OS-Path: /TimelogSvc
OS-Pta: /rest/Timelog
OS-Page: /GetTimeLog?EmailId=John08#BizNext.com.sg&Fromdate=2019-04-21&Todate=2019-04-27
Please also see my code below of the client.
AuthenticationContext authContext = new AuthenticationContext(authority + tenantID);
HttpClient httpClient = new HttpClient();
string s = string.Empty;
result = await authContext.AcquireTokenAsync(resourceUri, clientId, new Uri(redirectUri), new PlatformParameters(PromptBehavior.Auto));
// Append the token as bearer in the request header.
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
// Call the API.
HttpResponseMessage response = await httpClient.GetAsync("https://timelogapitest-BizNext.msappproxy.net/TimelogSvc/rest/Timelog/GetTimeLog?EmailId=John#bizNext.com.sg&Fromdate=2019-04-21&Todate=2019-04-27");
s = await response.Content.ReadAsStringAsync();
Mobile applications
I've worked around this by including the access token in a custom header (a second time). This assumes you have control over the backend so you can read that custom header. If necessary, you could even write this into the AuthHeader on the backend to ensure normal authorization flow from there.
HttpClient client = new HttpClient();
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, "API/URL/GoesHere");
// Add token to authentication header as per usual
message.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
// Custom header containing the token a second time.
// Name if whatever you like, just make sure you look for the
// exact name on the backend
message.Headers.Add("JwtAccessToken", token);
HttpResponseMessage response = await client.SendAsync(message);
string responseString = await response.Content.ReadAsStringAsync();
Web Clients
This seems to work now:
https://feedback.azure.com/forums/169401-azure-active-directory/suggestions/32386468-forward-incoming-jwt-token-to-backend-service#{toggle_previous_statuses}
I have a web api that is working great in test using an access token / bearer authentication. I authenticate and make requests using HttpClient. Easy.
Here is the basic web client setup. The base address is a constant that I change when moving to production.
public static HttpClient GetClient()
{
HttpClient Client = new HttpClient();
Client.BaseAddress = new Uri(Ics2Constants.ICS2APIBaseAddress);
Client.DefaultRequestHeaders.Accept.Clear();
Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return Client;
}
I build the token request login info like so:
var values = new Dictionary<string, string>();
values.Add("grant_type", "password");
values.Add("username", "niceUser");
values.Add("password", "NiCePaSsWord");
var loginContent = new FormUrlEncodedContent(values);
And then I make the request for the access token:
var loginResponse = await client.PostAsync("/Token", loginContent);
In test mode, perfect. I can get my access token, pass it back on subsequent requests. All is good.
When I move to production. I get a bad request 400 on the request for access token. I do have the base address right because if I take off the authorize attribute I can get data back.
Something is different about the request for access token in production, but I have no clue what to change.
Well, the answer ended up being two part:
1) Issue with the web host. They had a corruption on their end.
2) After they fixed their issue I still received a 404 (not found)... so I had to take out the "/" in my PostAsync. So the new line looks like so:
var loginResponse = await client.PostAsync("Token", loginContent);
It worked in debug on the local side with the "/", but the production side was not happy.
I'm up and working now. :)
The ServiceStack docs are full of examples on how to use server side implementation of authentication of a user. But how does one set the user credentials on the client side?
I use ServiceStack to consume a JSON REST service like this:
var restClient = new JsonServiceClient (baseUri);
var response = restClient.Get<MyResponse> ("/some/service");
How can I add any form of authentication to the request? The webservice I want to consume uses OAuth 1.0, but I am interested in adding custom authentication, too.
In my code, I have previously performed OAuth token exchange successfully, so I already own a valid access token and need to sign every REST request now using this access token and its token_secret.
ServiceStack's AuthTests shows different ways of authenticating when using the ServiceStack Service Clients. By default BasicAuth and DigestAuth is built into the clients, e.g:
var client = new JsonServiceClient(baseUri) {
UserName = UserName,
Password = Password,
};
var request = new Secured { Name = "test" };
var response = client.Send<SecureResponse>(request);
Behind the scenes ServiceStack will attempt to send the request normally but when the request is rejected and challenged by the Server the clients will automatically retry the same request but this time with the Basic/Digest Auth headers.
To skip the extra hop when you know you're accessing a secure service, you can tell the clients to always send the BasicAuth header with:
client.AlwaysSendBasicAuthHeader = true;
The alternative way to Authenticate is to make an explicit call to the Auth service (this requires CredentialsAuthProvider enabled) e.g:
var authResponse = client.Send<AuthResponse>(new Auth {
provider = CredentialsAuthProvider.Name,
UserName = "user",
Password = "p#55word",
RememberMe = true, //important tell client to retain permanent cookies
});
var request = new Secured { Name = "test" };
var response = client.Send<SecureResponse>(request);
After a successful call to the Auth service the client is Authenticated and if RememberMe is set, the client will retain the Session Cookies added by the Server on subsequent requests which is what enables future requests from that client to be authenticated.
Answering myself, as I've found a nice way to do it using the LocalHttpWebRequestFilter hook in the JsonServiceClient:
For securing a web service with OAuth 1.0a, every http request has to send a special Authorization: header. Within this header field, a hash (signature) must be send that uses some characteristics of the request as input data, like the hostname, request url and others.
Now it seems the LocalHttpWebRequestFilter is called by ServiceStack right before the http request is made, and exposes the underlying HttpWebRequest object, where one can add extra headers and access the required fields of the request.
So my solution is now basically:
var client = new JsonServiceClient (baseUri);
client.LocalHttpWebRequestFilter += (request) => {
// compute signature using request and a previously obtained
// access token
string authorization_header = CalculateSignature (request, access_token);
request.Headers.Add ("Authorization", authorization_header);
};
var response = client.Get<MySecuredResponse> ("/my/service");
Note that I use the Devdefined.OAuth library to do all the heavy stuff in CalculateSignature(). The creation of request token, obtaining user authorization, and exchanging the request token for access token as required by OAuth is done outside of ServiceStack, before the above service calls.
I'm using the new HttpClient class, part of the WCF REST Starter Kit, to authenticate to Google's Map Data service. I've got my ClientLogin authentication token, but I'm not sure how to take this instruction:
GET http://maps.google.com/maps/feeds/maps/userID/full
Authorization: GoogleLogin
auth="authorization_token"
and make it work in this code:
var auth = [myAuthToken]
var http = new HttpClient("http://maps.google.com/maps/feeds/maps/[myUserName]/full");
http.DefaultHeaders.Authorization = Microsoft.Http.Headers.Credential.CreateBasic("GoogleLogin", "auth=" + auth);
var response = http.Get();
The docs say: "the GET request requires an Authorization HTTP header, passing an AuthSub or GoogleLogin token." I have the token, I just don't know how to create that Authorization HTTP header correctly through that api. Anyone help?
Instead of using the CreateBasic static method, you can just pass the complete authorization header to the constructor of the Credential class. e.g.
client.DefaultHeaders.Authorization = new Credential("GoogleLogin auth=" + auth);