Sending cookie from client to web api - asp.net-mvc

In my client side (controller of MVC application) I am using the code below to set cookie value:
HttpCookie cookie = new HttpCookie("TestCookie");
cookie.value = 'Test';
HttpContext.Request.Cookies.Add(cookie);
I am also setting the cookie value in request header. This is done when I am configuring breeze entitymanager. I use breeze queries to get data from web api.
'Cookie': UserProfileID = config.getCookies('UserProfileID')
But in Web API, I always find that there are no cookies present in request header.
request.Headers.GetCookies("UserProfileID").FirstOrDefault()

To set a cookie, you need to add it to the Response object, not the Request.
var cookie = new HttpCookie("TestCookie");
cookie.Value = "Test";
HttpContext.Response.Cookies.Add(cookie);
Upon more research, I found this question. The answer provides some insight about the nature of Web API:
There's not a whole lot to work with here, but generally speaking, Web API diverges from MVC mostly in that it's fully REST-compliant, whereas MVC is not. REST-compliant applications are stateless (in other words: no session, no cookies, etc.). Everything the API endpoint needs must be sent along with the request either in the URL, the request headers or the request body. That means you could send the value of the cookie (not the cookie, itself) in the query string of a GET request or the body of a POST, or as is typical with REST API auth, as an Authorization HTTP header.
So to get your desired result, you would need to extract the value of the cookie on the client in your MVC application, then send it along as part of the data of your API request, or use an Authorization HTTP header as suggested.

Related

Call a Web API from MVC controller (cookie authentication)

I have a Web Api and Mvc 5 on same project.
That Web Api is protected with bearer token (but I commented the SuppressDefaultHostAuthentication line, so I can access the api from browser when I am authenticated with cookie mvc)
Now I´m trying to access the api from a mvc controller without sending the token, is that possible with SuppressDefaultHostAuthentication off?
Tried that without success (401 error):
HttpClientHandler handler = new HttpClientHandler()
{
PreAuthenticate = true,
UseDefaultCredentials = true
};
using (var client = new HttpClient(handler))
{
client.BaseAddress = new Uri("http://localhost:11374/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = client.GetAsync("api/MyApi").Result;
if (response.IsSuccessStatusCode)
{ }
}
If its not possible, how is the best way to handle that problem?
WebApi adheres to REST, which among other things, dictates that requests are stateless. That means with WebApi, or any REST-compatible API, there's no concept of anything such as cookies, sessions, etc. Each request to the API must contain all information needed to service the request. Therefore, if you have an endpoint that requires authentication, you must authenticate the request to access it. Period. If you're doing auth via bearer tokens, then you must pass the bearer token.
Since the WebAPI and the MVC app are in the same project you don't need to go through HTTP and make a request in order to access a method of each one - they're neighbors :)
You can treat the WebAPI as an ordinary class and instantiate it in the MVC controller. Afterwards you call the methods on the instance as you do with any other object in your application.
However it isn't possible to avoid tokens and/or other security mechanisms the WebAPI is designed with IF you leverage a request through HTTP to access it.

Download files in Javascript with OAuth2

I'm developing an single-page with Javascript+AngularJS on the client side and Spring MVC + Spring Security OAuth2 on the server side. Spring MVC acts as a REST controller for any AJAX requests from the page.
For authorization, the script sends an "Authorization: Bearer ..." headers with each AJAX request. This works fine when requesting small amounts of data.
To download XML files (export user data) I download them via AJAX, using the OAuth2 headers and create a Blob to allow saving the file in the browser:
var blob = new Blob([data.data], {'type': "text/xml"});
var a = document.createElement("a");
a.href = window.URL.createObjectURL(blob);
a.download = "downloaded-file-" + new Date().toISOString() + ".xml";
a.click();
This approach works but
Uses RAM and so is unsuitable for large file downloads
Does not show a proper progress/loading bar
So, the question is: is there a better way of downloading files with OAuth2 authorization? Javascript does not allow to specify headers when doing redirects, and OAuth does not allow to specify the authorization token via URL parameters. I'm thinking of either
adding a special Spring MVC controller method to provide an URL which redirects from an URL-encoded token to a header-encoded HTTP request
adding an extra Spring Security filter to allows extracting the token from URL parameters
moving to cookie-based authorization instead of OAuth2
If anyone had similar issues, could you please share your approach to this problem?
I would go with cookies if I were you - it takes all the hassle out of it. I wrote some blogs recently to show how easy it is (e.g. https://spring.io/blog/2015/01/20/the-resource-server-angular-js-and-spring-security-part-iii). People get too hung up on "stateless" applications.
Turns out it's very easy to to in spring-security-oauth2 2.0.7.RELEASE:
Simply pass the access token as the access_token request parameter:
window.open("service/export?access_token=" + access_token);
Now, this will appear with the access token in plaintext in the download history, so for proper security a "logout" option should be properly implemented, or the download will have to be done as a "form post".

iOS - How to get form data for an HTTP post

When submitting an HTTP post using Objective-C to a server, the required form data entries include __VIEWSTATE, __EVENTVALIDATION, username, and password. I get the user's username and password programmatically through the iOS application, but I hard-code the __VIEWSTATE and __EVENTVALIDATION parameters by looking at their entries through Google Chrome Developer Tools. The problem is that once the __VIEWSTATE and __EVENTVALIDATION parameters change, my app is defunct.
Is it possible to get the __VIEWSTATE and __EVENTVALIDATION parameters programmatically, possibly by storing them in a cookie, or can I send a POST request without them? Do I need to integrate a JavaScript function into my Xcode project?
It's strongly related to your server-side logic because it's a deal of client and server applications how to use this parameters, but in in most cases VIEWSTATE paramater is given to you at previous request. You should not send it with first request. For example:
request1, authorization — sending username, password. This will (may) return you VIEWSTATE.
request2 — sending VIEWSTATE from request1 and other parameters. This will (may) return you new VIEWSTATE.
request3 — sending VIEWSTATE from request2 and other parameters. This will (may) return you new VIEWSTATE.
...
I'm not aware about __EVENTVALIDATION parameter but you can inspect actual traffic from browser using debugging proxy tool such as Fiddler and try to find out logic of it's usage.

MVC .NET cookie authenticated system acessing a Web Api with token authentication

I have a Mvc 5 client that have a Ownin cookie authentication.
I also have a Web Api that is protected with Owin Bearer token (I used the VS2013 Web Api template, that create the Token endpoint)
Ok, now my Mvc 5 client need to use my WebApi.
I created a method to get the bearer token:
internal async Task<string> GetBearerToken(string siteUrl, string Username, string Password)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(siteUrl);
client.DefaultRequestHeaders.Accept.Clear();
HttpContent requestContent = new StringContent("grant_type=password&username=" + Username + "&password=" + Password, Encoding.UTF8, "application/x-www-form-urlencoded");
HttpResponseMessage responseMessage = await client.PostAsync("Token", requestContent);
if (responseMessage.IsSuccessStatusCode)
{
TokenResponseModel response = await responseMessage.Content.ReadAsAsync<TokenResponseModel>();
return response.AccessToken;
}
return "";
}
And in my Mvc action I called that:
public async Task<ActionResult> Index()
{
var token = await GetBearerToken("http://localhost:6144/", "teste", "123456");
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", "Bearer "+ token);
var response = await client.GetAsync("http://localhost:6144/api/values");
if (response.IsSuccessStatusCode)
{
var data = response.Content.ReadAsAsync<IEnumerable<string>>();
return Json(data.Result, JsonRequestBehavior.AllowGet);
}
}
}
That all works fine... But I need to use the Web Api in all my actions...
So how can I keep that token (despite getting a new token every request) and how verify if it expired ... Is it possible to keep that together with authentication cookie someway?
Any best pratices to deal with that scenario?
Thanks
If I get it right your MVC 5 client app is accessing a WebAPI of a different app.
The MVC 5 Client uses a cookie to authenticate the user. To access the WebAPI you get a Bearer tokeen from the /Token endpoint and send it in the Authorization header.
You do not call the WebAPI from your client side Javascript code, you just call it from within MVC Actions running on the server of the MVC5 application.
Getting a new Token before each service call sounds wrong. This would mean 2 roundtrips each time. This can't be performant.
If I got that right, you could:
Store the token in the Session object. For as long as your user of the MVC App is authenticated and his session is alive you would then always have the same Token.
If its expired you would get a 401 unauthorized access back from the WebAPI.
To keep your MVC Action Unit Testable you could wrap the session access into a Service that you inject into the Action (Dependency Injection).
you could store the Token in a cookie similar to the Authentication cookie already existing. This way you would not need a Session on the server side. Here again I would wrap the access to get the Token from the Cookie in a service that all your actions use.
I would use the Session storage. Simple. Straight forward.
But maybe I am missing something
Hope this helps you.
Feedback appreciated :-)
Bearer token is not a good way to authorize your web application. If you store services' token in cookie it will be available to the application's clients, so service layer will be vulnerable to application's clients. The only solution seems to be keep token in a session but you will lose stateless nature of your application.
Here is describied what/how bearer token should be used: "A bearer token is just a big, random string that a client must present on every API call. Bearer tokens are simple because there's no special signature or validation code required on either end. The client is responsible for storing the token in a safe place and sending it with every request. The server is responsible for looking up the token in a database and making sure it's a valid one -- that's it.".
Here is good example of using bearer token in single page application where client directly talks to the service.
Anyway I would suggest you to use HMAC authentication, BCrypt or ClientCertificates. Even amazon uses it for authenticating REST requests.
If you want to manage the tokens across all of your actions, you should change the code to use a custom authorization filter. That filter can be added to all Web API requests, all actions for a controller, or an individual action. To do that, derive from the AuthorizeAttribute and issue the GetBearerToken call from the filter. Stick the token into the HTTP context for usage during request processing. Instead of directly calling creating HttpClient instances, you could use a factory to generate them and add the appropriate tokens for authentication.
As for determining if the tokens are expired, you could add an additional filter that checks for specific errors coming back or alternative issue a check in the authorization filter. I don't know all of your requirements so it's difficult to determine the appropriate solution there.

asp.net mvc authentication when call from client app

I use asp.net mvc controller instead of Web Service in my project.
When I call the controller from my client app,there will be a authentication problem. If I use Web Service ,I can use SOAP Header , but now in asp.net mvc, There is no soap header.
Please help.
I am really know a little about the web security.
Normal way of doing this when you come to http services is to pass it in authorization header in following format (if you are doing request from fiddler)
Authorization: Basic user123:pass123
user123:pass123 string is normally base64 encoded and you have to decode it on server side, check it against user store and authenticate the user. One example can be found here
You have several options.
Use a request header to contain some security token.
Include security tokens in the message that you send in the request body.
If your application uses something like Forms Authentication, you can ask consumers to call a login action, then grab the Forms Auth cookie and include that cookie in subsequent calls.
Since you are not using soap. You may use a simple http way. Which means you start a HttpRequest and handle result via HttpResponse. Thus you have to simulate a authenticate action as signing in from web browser.
You need to get the security token or cookie from the reponse. And put them into your following request. Thus your controller will recognize the request's identity.

Resources