Clarify how cookies are working between Angular and c# controller - c#

I would like to clarify how cookies work between angular app and the c# server controller.
This is what I gathered from various discussions and forums:
The angular client sends HTTP Request (e.g. to login) to the c# server
c# server creates the cookie (e.g. refreshToken) using:
Response.Cookies.Append("refreshToken", token, cookieOptions);
c# server returns and the cookie refreshToken is set in store on the client side
Whenever the angular client sends the HTTP request again, the cookie is set in the Request object (probably by the browser, behind the scenes - angular client does not explicitly set the cookie)
c# server receives the request and retrieves the cookie like below:
var refreshToken = Request.Cookies["refreshToken"];
Is my understanding correct?

Yes, your understanding is totally correct.
One note: Angular HttpClient does only include cookies for cross-domain requests (like in dev environment) in the request if HttpOption withCredentials is set to true.

Related

Redirect to a page with api response in ASP.NET Core MVC

I have an api controller with a http GET method. This method is invoked from a frontend. In response to this, I want to redirect user to dashboard page and also provide some login response object. When a request comes into this method, it comes from a different page.
The request comes to this method with a path api/accounts/loginobject when a third party identity servers sends oauth2 authentication. This is a redirect url method.
[HttpGet]
[Route("LoginObject")]
public async Task<IActionResult> getLoginObject()
{
var externalLoginInfo = await this.signInManager.GetExternalLoginInfoAsync().ConfigureAwait(false);
// parse token here
}
I tried below code and it works. But I don't know if we can send response object in the below response. I want to attach token in the headers and some info in the response body.
// dashboard is a ui page not another controller action
return Redirect("/dashboard");
The front end app is an angular app part of ASP.NET Core MVC project. I have a third party identity server which sends oauth2 result back to this controller.
The following will set header but it will be lost when the redirection to html page /dashboard happens. Still I am not able to respond to ui with access token
this.Response.Headers.Add("Authorization", $"Bearer {accessToken}");
Update:
I solved this temporarily by passing token in query string. It looks more like a hack for now. Once received it in ui, i will set it in web app local storage for subsequent api calls.
https://mywebsite/accesstokencallback?access_token=eybcsdfk23klsd-3dsfjs

My web browser won't store the cookie from the response header

I have an API located at http://localhost:57780.
When I attempt to call the login endpoint from my client (http://localhost:4200), I receive my cookie in the response header AND it is successfully stored in the browsers cookies.
Now, here is my issue: Using the same API, I now call the login endpoint from my client at a different DOMAIN (http://127.0.0.1:4200).
I still successfully receive my cookie in the response header ALTHOUGH the browser is not storing this cookie.
I am using the HTTP interceptor so that each call has withCredentials set to true.
I have also set Access-Control-Allow-Origin to AllowAnyOrigin.
What am I doing wrong?
P.S: This is my first stackOverflow post so any tips would be greatly appreciated :)

How to authenticate an HttpClient connection with an external provider (Google)

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.

HttpClient requests ssl website, but cannot get cookie in uwp

I'm using httpclient to request a ssl(https://) site. But I note that even if I can get response from that site, but the site still hasn't set cookie in my local. So, I cannot read cookie from filter.CookieManager.GetCookies().
I guess that's due to I have not add certificate when posting data.
I done another testing, I used webview to open this site, then I can get cookies by CookieManager.GetCookies.
So, my question is how I can use httpclient to request "https://" site and make it write cookie in my local.
Read the documentation here for the cookies from response. There is also a working example available.

Web API how to secure token when using IFrame on clientside

I have a ASP.NET Web API server application and Javascript frontend.
The way Im implementing authentication is by using a Token that is sent and received in the HTTP Response Headers.
When the users log into the application, my server will send back to the client a JSON object with a session Token. The javascript client then stores that in a browser cookie.
Every call that the javascript client makes to the server, the token is sent in to a custom header so the server can decrypt that and validate it in the database so it know if its a valid session.
Everything works great here, If I need to secure that part then adding a SSL will help.
Now, there are calls in the app that I need to use an IFrame so I set the src property to the web api method I need to call.
It's not possible to add a custom HTTP Header when using IFrame, just a simple URL into src property
Of course using this there is no way to send a custom header so what I did was to append a parameter into the scr url like this:
<iframe scr="/api/report/GenerateReport?sessionUid=" + getCookie('sessionuid') ></iframe>
This is my web api method that receives the sessionUid as a parameter.
[HttpGet]
public HttpResponseMessage GenerateReport(string sessionUid) {
// validates session
bool validSession = common.ValidateSession(sessionUid);
if (validSession) {
// do some stuff here
}
}
My question is... how can I secure my token, because if someone steals the sessionuid he then can call all the HttpGet methods that receives sessionUid as a parameter?
Any clue?
If your website is not using SSL, then you cannot 100% secure the communication between your website and user's browser.
Attackers usually hijack you whole HTTP package, including HTTP headers, put session in HTTP header is not enough for security.
The answer to your specific question is to encrypt the querystring parameters.

Categories

Resources