is it possible to have a simple explanation of what is the LogoutPath?
options.Cookies.ApplicationCookie.LogoutPath = "/Account/LogOff";
The docs say nothing about that and the info gotten via intellisense or here
https://msdn.microsoft.com/en-us/library/microsoft.owin.security.cookies.cookieauthenticationoptions.logoutpath(v=vs.113).aspx
is all the more confusing grammatically. I do not see how to implement it when redirecting a user once logged out.
@Ponant you are so correct about this imo. I looked around to see what authors were saying about it, and I'm shocked to see authors around the Net not explaining it better.
It comes into play in the signout here: https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationHandler.cs#L315-L317
... where you see at the end of the end of the HandleSignOutAsync() task ...
c#
// Only redirect on the logout path
var shouldRedirect = Options.LogoutPath.HasValue && OriginalPath == Options.LogoutPath;
await ApplyHeaders(shouldRedirect, context.Properties);
LogoutPath is a convenience setting. Instead of you having to sign your user out manually after HandleSignOutAsync() with your own line of redirect code, all you have to do is indicate to the middleware with LogoutPath where your controller action is that you're triggering the HandleSignOutAsync(). The middleware will take the returnURL query string parameter from the request URL and redirect the browser there after the user is signed out.
You could just as easily accomplish this by not setting the LogoutPath and then having a line of code to redirect the browser after you call HandleSignOutAsync(). It really does just save you a line of code.
@rustd @Rick-Anderson @tdykstra @Erikre are the authors of Introduction to Identity, so they'll have a better sense if this info should be provided and where.
Thanks to @pinpoint for clarifying this to us. He'll jump in here if I went astray anywhere.
cc/ @blowdart
@GuardRex , so you mean that in our example, /Account/LogOff will be the ReturnUrl and hence the action the user will be taken to after he has been signed out? Thanks
No ... the /Account/Logoff path will be to your controller action where you call HandleSignOutAsync().
Out in your app where you have a logoff link, you'll set the destination of the link to something like /Account/Logoff?returnUrl=/, which would send them to your /Account/Logoff controller action, log them off with HandleSignOutAsync(), and then the middleware will automatically redirect them to the homepage (i.e., whatever it finds in the returnUrl parameter; in this case, it's just a slash /, so that would be the homepage).
If you were to have the link go to /Account/Logoff?returnUrl=/thanks, then the log off would occur and the browser would be redirected to /thanks ... another controller action where you'd serve a "Thank You for using our system!" page.
See ...... all LogoutPath does is tell the middleware that when it finds a returnUrl on the request path that you have for LogoutPath="/Account/Logoff" that it should use that and automatically redirect the user after you call HandleSignOutAsync(). That's why I was saying that you could skip setting LogoutPath and put a line of code after HandleSignOutAsync() to redirect them yourself if you wanted to do it yourself.
I kind of see, but honestly, not quite! I was going through IdentityOptionsand have set this option in ConfigureServices to check it out. I am using the SignInManager to sign out and I do not see how to call HandleSignOutAsync (it is protected, btw). My controller is very basic
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logoff()
{
await _signInManager.SignOutAsync();
return RedirectToAction(nameof(HomeController.Index), "Home");
}
I tried to add a returnUrl in this action and have set the logoff button with an asp-route-returnUrl="/home/thanks" for testing but it does nothing. Anyway, probably I need to dig into it with a fresh look. I expect there is some good reason why this is so here.
Cheers
I do not see how to call HandleSignOutAsync (it is protected, btw)
Yes. My bad. I was just mentioning it from looking at the reference source code. You are correct in that SignOutAsync() is the correct call. I should have recognized that HandleSignOutAsync() is called behind-the-scenes to get the user logged out.
I checked all of the sample apps, and they apparently all do a RedirectToAction() manually. In theory with the LogoutPath set and a returnUrl on the request it shouldn't be necessary to manually have RedirectToAction() on these Logoff() methods. They'll jump in and correct me if I'm wrong about that.
```c#
[HttpPost]
[ValidateAntiForgeryToken]
public async Task
{
await _signInManager.SignOutAsync();
return new EmptyResult();
}
options.Cookies.ApplicationCookie.LogoutPath = "/Account/LogOff";
```
The alarming thing to me about this (I agree with your OP): I don't think it's explained well anywhere I can find ... not just around here ... I mean across the Net.
But that is my point, what do you return? I do not think your Logoff will compile because SignOutAsync will return void.
ApplyHeaders() goes to RedirectToReturnUrl() ...
... it ultimately lands on OnRedirectToReturnUrl ...
... where the Location header is set ...
context.Response.Headers["Location"] = context.RedirectUri;
Therefore, it should be sufficient to return an empty action result. I modified the example above to do it.
I see this approach in a @pinpoint issue: https://github.com/aspnet/Mvc/issues/4258
Thanks @GuardRex , in overall I think this stuff needs clarification, and I expect a simpler procedure to make use of LogOutPath.
I have seen this, but the accepted answer is not so clear neither:
http://stackoverflow.com/questions/29785252/does-logoutpath-do-anything .
In any case, I can only recommend to enhance the presentation of the ASP.NET Identity-
Yes, indeed. I agree with your OP. Even when I asked @pinpoint about this, he said, "Good question!"
@Rick-Anderson @tdykstra TL;DR The LogoutPath might not be well explained anywhere ... as in "anywhere on 馃實 Earth" :smile:. If you would like me to take a stab at 2-4 sentences on it for the Introduction to Identity doc, let me know.
@GuardRex Yes, thanks, that would be great.
@Rick-Anderson One little thing tho that you'll have to decide on this ...
The code shows the LogoutPath set ...
```c#
options.Cookies.ApplicationCookie.LogoutPath = "/Account/LogOff";
... but the way the controller action is setup ...
```c#
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> LogOff()
{
await _signInManager.SignOutAsync();
_logger.LogInformation(4, "User logged out.");
return RedirectToAction(nameof(HomeController.Index), "Home");
}
... it doesn't look like it will ever work. If this action is hit with a returnUrl set on the request URL, it will set the Location header to whatever you provide for returnUrl; however, when it drops down to the RedirectToAction, it looks like it will do a 302 redirect and overwrite the Location header value (presumably). Regardless of the value for returnUrl, it looks like the browser is going Home.
Soooo ... what would you like to do ...
LogoutPath, and I'll add a short paragraph to talk about it as an optional setup, where I'll say that the controller action should return an EmptyResult instead of a RedirectToAction.RedirectToAction. Don't talk about the LogoutPath property here or show it at all.returnUrl won't work with the RedirectToAction in place.EmptyResult. An added paragraph will explain what it's doing.Choice 5 looks interesting. Anyway, yeah ... let me know.
I feel confident in the behaviors from looking at the OP on the @pinpoint issue https://github.com/aspnet/Mvc/issues/4258 and talking to Kevin on Slack ... I'd feel a lot better if my good friend would put an :eye: on these options for a @GuardRex sanity check.
@GuardRex , I may be wrong but my gut feeling is that there is a simple way to make it work than returning an EmptyResult(which looks weird). Perhaps someone at MS knows that, somehow .Net has been written by humans, I assume ;), so there must be a practical reason which goes beyond saving one line of code...
BTW, I would take this opportunity to check out all the options with small pieces of codes when needed explaining what they do (even if obvious). For instance at some point I struggled to understand what was the difference between access denied and unauthorized paths, until I read it somewhere, after which it became obvious.
@HaoK TLDR; can you explain LogoutPath ?
` options.Cookies.ApplicationCookie.LogoutPath = "/Account/LogOff";
That path is what the cookies middleware will redirect to after a sign out has been processed. Basically its used to display the "You have been logged out" confirmation to the user.
But if the controller action redirects Home, is that the behavior?
No the controller will win.
Basically cookies will set one redirect as part of the call to sign out, then the controller will set a different redirect after (last one wins)
In that case, should the sample even show it being set?
If it remains, do u think that there should be additional language to explain it? If not, then IMO this can closed as a don't-fix.
Should probably just remove the explicit setting of that property
Excellent ... @Rick-Anderson I'll get that in in shortly if u like.
@HaoK , can you show a simple running example on a post IActionResult?
Example of what exactly?
An example of "You have been logged out" using the cookie.
Durr brain fart sorry actually I take back what I said earlier, I was thinking of how AccessDeniedPath works, LogoutPath is actually something completely different, that is actually a security setting that makes sure that the cookie middleware only redirects calls to SignOut when the Request path is the LogoutPath.
Basically its to the middleware from trying to redirect to the return url if SignOut("Cookies") is called on pages other than log off
So in that case it stays, but it still seems like it wouldn't effectively honor a returnUrl query string parameter set to a non-Home path when the controller action is going (in this case) to send the browser Home. Is that correct?
I posted this question because I was basically struggling making it work like an AccessDeniedPath. Hence my question on how you would use it, in code, not in words (to minimize confusion).
I can formulate the question differently: Once the user has set:
options.Cookies.ApplicationCookie.LogoutPath = "/Account/LogOff";
what should he set in his controller to effectively use this LogOutPath?
Yes I was confused for the same reason. AccessDeniedPath is used to configure what happens on 403s. This is more like telling the cookie middlewhare what the app's logout url is, so it knows to only redirect on signouts from that page. You don't use the LogoutPath, you are telling cookies what your logout page is (basically enabling redirects back to return urls after sign out on this page only)... completely different from AccessDeniedPath which cookies generates redirects to...
So the answer to your question is you don't use this logout path at all in your controller, but it just should match the actual logout path.
it knows to only redirect on signouts from that page
I'm with you. The action item then for the doc (in this case the way this controller action is setup) is to remove ...
options.Cookies.ApplicationCookie.LogoutPath = "/Account/LogOff";
... from the sample. It won't work (returnUrl will not be honored) with a forced 302 redirect to Home (RedirectToAction).
I believe the original idea is that its trying to keep you on the same page you were at, so if you were in About, and click Logoff, that will generate a returnUrl to /About, and will redirect you back there.
But yeah the templates today no longer seem to support that scenario, I just tried it and it just sends you back to Home... so its either a bug (or the new behavior). You could file a bug in the templates repro asking what the desired behavior is as well...
Thanks @HaoK ... In that case, it's best not do anything here until the desired behavior is determined. I'll open an issue over there and ask.
@Ponant You can leave this issue open. Either a team member will close it if no action is to be taken or it will automatically close with a merged PR.
A few guys are using the LogOutPath, though, so somehow it should work.
https://auth0.com/blog/authenticating-a-user-with-linkedin-in-aspnet-core/
https://github.com/jerriep/aspnet-core-oauth-linkedin
I think the key point is that they app.Map to the logout route.
@HaoK There isn't a cookie auth sample over in templates. There's the Identity sample over in the Identity repo. The CookieAuthenticationHandler bits are over in the Security repo.
Should I proceed with an issue in Templates? ... or is one of the other repos a better spot?
This is just an app question, basically should we logout preserve the current url rather than redirecting to home, since as we just discussed, setting this isn't very useful at all if we already just redirect to home...
I see, so it is more of a "what should the templates (and samples) show" kind of question. Ok, thanks.
@GuardRex and .Net guys;, an advice, believe me, the underlying structure of all .Net Core is difficult to get from the docs. You get the surface of what is going on, which is great, but very quickly you need to dig and bypass standard procedures to make a real app. And here, you are quikly left with one-line intellisense or outdated info from the full .Net. Take for instance the ASP:NET Identity. The tutos are great for copy paste guys but then you are oriented to the idea that everything is Claims, and here the documentation is scarce. This is why I would not hesitate to add info on the docs more than removing it, and would not hesitate neither on showing up some code which users will ultimately use beyond templates. I started with the template a few month ago as being introduced to .Net but that was good only for learning a bit of the pieces, from ViewBags to EF and middlewares. Since then, I am making a new app from scratch and this is where questions of the sort come up.
@GuardRex TLDR - should we close this issue an open a new one with what you decided?
@Rick-Anderson AFICT and IIRC the issue at https://github.com/aspnet/Templates/issues/831 covers it, so I think you can close here. If they change the behavior, then I guess a new issue linked to that Templates issue makes sense, yes. However if they don't make any changes via that issue, then a new issue over here probably isn't needed.