I want to implement a single sign on feature using my own API. Third party application(web application) will call this API and authenticate the users. For the communication between my API and other applications web request will be used. Below is the solution I provided for this,
I have created a API on my application and do the authentication based on request values. After successful authentication, I create the authentication cookie and add it to the response.
On the other app I used a HttpWebRequest and create CookieContainer. Then I get the cookies from response and assign those cookies to Response.
var response = (HttpWebResponse)http.GetResponse();
foreach (Cookie cook in response.Cookies)
{
Response.Cookies.Add(new System.Web.HttpCookie(cook.Name, cook.Value)
{
Domain = cook.Domain,
Expires = cook.Expires
});
}
In my test environment this works fine since both authentication API and other app are in same domain. But in customer testing phase this does not work due to domain mismatch. Because Authentication API is in different domain.
Is there any way to resolve this issue ?
I think it is impossible with cookies because they are domain bound and are not sent along with requests to domains. I guess you need see about other technology.
I hope this link will be useful
Good Luck
Related
Edit:
Here is my question reformulated:
I have a web server with secured api endpoints - one must have been authenticated with Google prior to using them. I implemented Challenge and Callback endpoints for that.
This works well from a browser with my SPA web front-end. The user gets redirected to the Google website to sign-in and then gets redirected back to my webapp; the browser then has the authenticated cookies and the webapp can use the endpoints to update its state.
I also have a WPF application that will communicate with the web server.
I want the WPF application to do the same as the web front-end: Use the web api endpoints after being authenticated with Google. The connection between the WPF application and my web server is done through an HttpClient.
My problem is I don't know how to authenticate that HttpClient connection between the WPF app and the web server.
I tried using the same Challenge endpoint but the response I get is of course the HTML from the Google Sign-In page, so I guess I can't use that with an HttpClient...
I also tried authenticating with GoogleApis from the WPF app and use the authenticated token to set cookies in the HttpClient but apparently this is not compatible.
How to authenticate an HttpClient connection to a web api with an external provider such as Google?
Original question:
From a WPF application, the user authenticates with Google with this code:
using Google.Apis.Auth.OAuth2;
...
public void Authenticate()
{
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId = "myClientId",
ClientSecret = "myClientSecret"
},
new[] { "email", "openid" },
"user",
CancellationToken.None).Result;
}
This works and the UserCredential object contains the authenticated token:
How to embed this token information in a web request made with an HttpClient in order to call my webapi endpoint?
I think the request must include some cookies to inform the server that it has been authenticated, but I don't know which ones exactly.
The endpoint on the server-side validates that the user is authenticated with the help of IdentityServer:
var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);
if (result?.Succeeded != true)
{
throw new Exception("External authentication error");
}
If I got your question right, you just have to set the Authorization header
var credentials = await GoogleWebAuthorizationBroker.AuthorizeAsync(
clientSecrets,
new[] { "email", "openid" },
"user",
CancellationToken.None);
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
credentials.Token.TokenType,
credentials.Token.IdToken);
Maybe you'll find below a helpful hint to better understand OpenID :)
The confusion stems from mixing GoogleApis and IdentityServer frameworks.
Authentication/authorization can be achieved using either of them.
Objects from Google.Apis.Auth.OAuth2 and IdentityServer4 namespaces are not designed to interact.
No manual cookie handling is necessary, for sure.
Ask yourself to whom does Google provide trust for the user. If it calls back to WPF, then webapi trusting WPF is a separate issue.
You answer your own question in the question:
the browser then has the authenticated cookies and the webapp can use
the endpoints to update its state
HttpClient needs to send those same cookies.
How do I set a cookie on HttpClient's HttpRequestMessage
If I understood your question right, then I faced the same problem not too long ago.
The way I implemented it is that in the backend, no matter who tries to access the endpoint, they had to send a Bearer X authorization token.
The token contained the identity of the client that wanted to access the resource, and I checked if he was permitted.
No matter what kind of client wants to access the endpoint, it just has to have that authroziation header in the request that he sends and the backend will treat it the same.
In my scenario, I used an authentication service that returns a cookie to the client with a certain JWT that contains the identity information.
Then from the client I send in every request the JWT received from the authentication service as an authorization header to the backend.
The reason I had to put the JWT that I receive from the service in a header, is that the authentication service and the backend service are not in the same domain, so cookies cant be shared.
This results in such design that no matter how you authenticate the client, the end result must be some sort of token that the backend can receive and read.
Hope this helps.
I know this is very common question. But I really do not know how to integrate it.
I want to add authentication to my web api services. Right now I have created one console application to call service's method.
I have gone through this blog. I just want to implement authentication filter as mentioned in this article.
I want to know how can I pass credentials along with HTTPClient from my console application, fetch those things to web API and authenticate them.
I have created authentication filter but it does not invoke AuthenticateAsync method of authentication filter.
To pass http client I have done this:
public void GetData()
{
HttpClient cons = new HttpClient();
cons.BaseAddress = new Uri("http://localhost:50524/");
cons.DefaultRequestHeaders.Accept.Clear();
cons.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var data = Encoding.ASCII.GetBytes("Ankita:ankita123");
var header = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(data));
cons.DefaultRequestHeaders.Authorization = header;
//MyAPIPost(cons).Wait();
MyAPIGet(cons).Wait();
}
Teaching you how to implement authentication in Web API will take a lot of time. You better stick to online tutorials.
The blog you've read tackles about different authentication for ASP.NET. Since you've tagged your question as ASP.NET Web API 2, I would suggest using a token-based authentication utilizing OWIN middleware. Check this out. The guide uses a console application for checking the requests to the web API.
The gist of it is...
Client > Token Provider (Generate token for valid user) > Web API > Check if Token is Valid (Existing and not expired) > Authenticate!
Considering you are trying to access the API with an HttpClient, you can pass it an instance of HttpClientHandler when creating it, which allows you to set the credentials that will be used when it performs requests:
new HttpClient(new HttpClientHandler { Credentials = new NetworkCredential(userName, password) })
Hope it helps!
I have successfully implemented authentication using this article. In that filter attribute is implemented.
We have a desktop application that requires authentication with a server in order to operate. This application prepares and sends a query to a webservice, the user is prompted from this webservice to log in and the webservice returns an XML document with application subscription information (Software-as-a-Service Subscription License).
I've created a WebApi webservice that does the following:
Accept incoming request at /api/client?[MACHINEINFOINQUERYSTRING]
Redirect to external authentication provider (think GoogleId or
similar)
Authentication provider sends information back to
/api/subscription/[AUTHENTICATIONID]
The /api/subscription endpoint returns an XML document after pulling info from the servers (or including appropriate error message).
This webservice works and the XML document can be viewed in the browser. I've created a website with a default.aspx to test this, automatically redirecting to the /api/client and it does display this XML document in the browser.
The desktop application properly makes the initial call, redirects through an embedded browser to the login page, and receives an XML, but this XML cannot be parsed. The application team simply gets a "download" option for the XML but cannot capture the response for stuffing into an XmlDocument object. I've attempted to create an example application to instruct the app team, but have had no success.
Questions:
Do I have this architecture fundamentally wrong or do we simply not know how to consume the response properly?
How do I capture and consume the XML that is successfully returned?
As an example of what I've tried:
string requestString = string.Format("http://[server]/api/client?{0}", HttpUtility.HtmlEncode(queryString));
Response.Redirect(requestString);
This works in the browser, displays the login page, allows for input, redirects to the subscription endpoint which then prepares and delivers the XML to the browser. Unfortunately, this is unusable by a consumer.
HttpWebRequest request = WebRequest.Create(requestString) as HttpWebRequest;
request.AllowAutoRedirect = true;
request.MaximumAutomaticRedirections = 20;
request.AuthenticationLevel = System.Net.Security.AuthenticationLevel.None;
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
This doesn't work. The response.ResponseUri has the properly formatted address of the OAuth service (step 2 above). It does not display the login page to the user even though this is all initiated through a browser.
I've also tried using a WebRequest POST, HttpClient PostAsync and several other methods, but:
The response URL is simply the location of the login page. If I string together 3 WebRequest/WebResponse pairs, it fails because the user isn't being properly authenticated at the first request / initial redirect.
What does work in my default.aspx:
I haven't found an example online for my specific needs, but the pattern must exist in practice as plenty of websites utilize OAuth style logins. I've utilized webservices (like OData endpoints) that also require logins, so this pattern must exist for webservices too. I do send back a properly formatted XML document. We just don't know how to capture and consume that document.
Any examples of a similar architecture would be highly appreciated! Or pointing me in the right direction.
Edit ---
I'm thinking that somehow the request.GetResponse() isn't really allowing for redirects and/or since it's an HttpWebRequest, there's no way it will allow for user input.
What's the proper way to make this call and consume the XML from another application? the XML is delivered properly in a browser window (with Response.Redirect) but no login window opens using an HttpWebRequest.
The answer is: This architecture is fundamentally wrong.
OAuth architecture leaves the authorization to the client, which then sends an authorization token to all subsequent services that it requires. The services are simple endpoints and do not contain any authentication logic, (although the service itself is allowed to validate the authentication token with the OAuth server).
The proper sequence of events for this answer should be:
1) Desktop Application makes OAuth authentication request to authentication server.
2) A successful response includes an authorization token which contains identity information, permissions, validity period, etc.
3) The desktop app then requests information from the WebApi service, sending in the request that token.
4) WebApi takes this authentication token, validates it (in my case against a certificate) and may even query the OAuth server again to ensure that the token is still valid.
5) If valid, the web service gathers the data and sends it back to the server.
My problem was I was expecting the subscription service itself to be able to open a web browser, prompt for a login, and then continue the request to another endpoint (2 redirects after initial request). I was in effect, breaking both the WebApi and OAuth 2 designs. Although it worked from the browser, it was not consumable from an application.
After redesigning to this simpler pattern, my web service is now consumable.
I have two webprojects: MyApp and Api.MyApp. MyApp is an MVC5 Application and Api.MyApp is a MVC WebAPI application.
MyApp is a rich client application that calls the API project for most of its operations. For authorization I am using a Bearer token for the web api but I would also like to have a cookie
so I can secure certain routes in the main MyApp MVC project.
To get the bearer token I call "http://api.myapp/token" can I throw this bearer token into a cookie and have the MVC project recognize it or do I have to send 2 separate calls, 1 to the api to get the bearer token and 1 to the mvc app to get the cookie. This seems a little redundant, is there a better way?
Yes.
Assuming your applications are responding on something like:
api.example.com
www.example.com
The user comes to your site on www.example.com and provides their credentials. Your app then makes an AJAX call to api.example.com to get the token. You have a couple of options now:
api.example.com returns the token, along with a cookie, with the domain set to .example.com
api.example.com returns the token, and the client-side script sets that into a cookie with the domain set to .example.com
If you do this, then both the API and the client application should have access to the cookie based token.
You may have to roll your own authorisation mechanism based on the bearer cookie if you're not using .Net auth tokens.
If however you are on intranet type domains (i.e. http://myapp/ and http://api.myapp) then you'll have to go with option 2 and use the default domain for the cookie (you can't set a cookie with just a single period in the domain otherwise I could set one to ".com" and splurge data everywhere.)
I'm creating a web service to expose some data via publicly accessible APIs. At a high level, what mechanisms are people using to secure their APIs to ensure that a valid, authenticated user is making the call?
The service will be C#, the consumer could be anything (Facebook or iPhone app as well as a website) so Microsoft only solutions are out.
It's not a new problem so I assume there are some standard practices in place to deal with it but my google-fu is failing me on this one. Can the collective point me to any resources? Thanks.
You can still use Membership authentication: have a web service method Login(username, password), inside that method validate user:
[WebMethod]
public bool Login( string username, string password)
{
bool isValid = Membership.ValidateUser(username, password);
if (isValid)
{
FormsAuthentication.SetAuthCookie(username, true);
return true;
}
return false;
}
And that should do it - it will create a cookie that travels with requests and in each method you can check HttpContext.Current.User.IsAuthenticated.
void SomeWebMethodThatRequiresAuthentication(someparameter)
{
if (HttpContect.Current.User.IsAuthenticated)
{
... do whatever you need - user is logged in ...
}
else
{
.... optionally let user know he is not logged in ...
}
}
I believe it can work with different consumers that support cookies because all it needs to work is for consumer to send the auth cookie along with the request to your web server.
I see that ferequently in SaaS web services is used authentication by token key over SSL - we choose this simple method in our last project over OAuth and SAML protocols. Maybe this can be usefull - sometimes simple solutions make things more scalable and over control.
Try the answers in this similar question:
What is the best way to handle authentication in ASP.NET MVC with a Universe database?
We use the WS-Security. It's a published standard so any client (in theory) can use it to send authentication credentials.
Here's another SO question that covers using WS-Security with C#.
How to use WS-Security in C#?