How to manage/use the token returned (on successful login) by a webapi provider?

ssruk2019

New member
Joined
Jun 13, 2019
Messages
3
Programming Experience
3-5
Hi,
I am trying to add online appointment booking functionality to an existing website which is built using Umbraco. And using a third party web api service to implement this booking functionality. This web-api provider also handles the login part to authenticate the user and returns the XSRF-TOKEN which i need to use(implicitly) to call their other APIs. So far i am able to get this token and add it to DefaultRequestHeaders (inside the same controller)like:
C#:
public class AccountController : SurfaceController
   {
       HttpClient client;
       CookieContainer cookies = new CookieContainer();
       string token;
       public  AccountController()
       {
           HttpClientHandler handler = new HttpClientHandler();
           handler.CookieContainer = cookies;
           client = new HttpClient(handler);
           client.BaseAddress = new Uri("url");
           client.DefaultRequestHeaders.Accept.Clear();
           client.DefaultRequestHeaders.Accept.Add(new
           MediaTypeWithQualityHeaderValue("application/json"));
       }

       public async Task<bool> ValidateLogin(LoginModel model)
       {
           HttpResponseMessage responseMessage = await client.PostAsJsonAsync("url", model);
           Uri uri = new Uri("url");
           IEnumerable<Cookie> responseCookies = cookies.GetCookies(uri).Cast<Cookie>();

           token = responseCookies.FirstOrDefault(x => x.Name == "XSRF-TOKEN").Value;
           if (!String.IsNullOrWhiteSpace(token))
           {
               client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("X-XSRF-TOKEN", token);
               client.DefaultRequestHeaders.Add("X-XSRF-TOKEN", token);
               return true;
           }
           return false;
       }

       public async Task<ActionResult> GetUserDetails()
       {
           HttpResponseMessage responseMessage = await client.GetAsync("url");
           if (responseMessage.IsSuccessStatusCode)
           {
               MyViewModel model = new MyViewModel();
               var responseData = responseMessage.Content.ReadAsStringAsync().Result;//Getting an unauthorised response back here since the token is not handled as required

               model.UserDetails = JsonConvert.DeserializeObject<MyViewModel>(responseData);
               model.Appointments = await GetAppointmentsByUser();
               return PartialView("_UserDetails", model);
           }
           return CurrentUmbracoPage();
       }

       private Task<object> GetAppointmentsByUser()
       {
          //Code
       }
So now the real problem is how to manage/handle this token so the logged user can get authenticated to use other GET, PUT,POST requests?
I'm new to webAPI and MVC authentication so detailed explanation to the solution will be appreciated.
Can you guide me to implement this in a proper way please?
Thanks in advance.
 
Last edited by a moderator:
How do you know that the same instance of your AccountControllercontroller is being used between for the call to ValidateLogin() and GetUserDetails() ?

Right now you are stashing the XSRF-TOKEN into client.DefaultRequestHeaders, but client is an instance variable. If two different instances of the controller are in play, then they will not share their instance variables. Let me warn you know that using a static class variable is not the correct solution because now all instances will share the same client which is likely not what you want to happen when two different people are logging in at the same time.
 
Yes thanks but I know this already, this is why I was looking for a help. I'm also aware know this is not correct implementation. Actually I am a newbie in API development and never done this part of the HTTP configuration before so expecting sort of guide/Reference/pointer where I can find the proper implementation solution for this.
 
I was actually trying my best to avoid alluding to that code project article (I ran across it several years ago) because it is dealing with things at the "application" level vs. your current code which is doing things at the "controller" level. Furthermore, the common theme in that article was that he is recycling each of the HttpClient because he is using them in a more or less stateless manner. Any state he sets up is shared state. In your case, you need a per-user-login state is my understanding.

Notice that at the end of the article, he has shows how to deal with just a shared HttpClient but the actual message being send has varying content ( HttpRequestMessage). In your case, your content needs that X-XSRF-TOKEN set. Which brings you back to the original problem, where do you store the per-user value of XSRF-TOKEN so that you can set X-XSRF-TOKEN at the appropriate time?
 
Here are the steps use token using Web API project:
  • Create & configure web API project
  • Install the required OWIN component using Nuget packages
  • Create a DBContext class
  • Define an OWIN start-up class
  • Configure OAuth authorization server
  • Test the project
 
And how does your solution help the OP? Your solution is for the case where the OP is the author of the web service, but in this case the author is the client of the web service.
 
It's an interesting article. I remember seen this argument somewhere before, but I also remember agreeing with the arguments being made regarding how a httpclient should be used and for what duration, and should they be destroyed and disposed etc. @Skydiver Have you read Darrel's comments in this link below?
Do HttpClient and HttpClientHandler have to be disposed between requests?

And can someone please fix the code tags. It's difficult to read like that...
 
I've not seen that particular SO question so I've not seen his specific comments, but I have seen Darrel's blog post before. Basically, keep using the same instance as much as you can. If it's different sessions, then dispose it. In our OP's case they are trying to use the same session.
 
Back
Top Bottom