Logging Out With AspNet.Security.OpenIdConnect.Server (ASP.NET vNext)
Asked Answered
T

1

2

I am using Visual Studio 2015 Enterprise and ASP.NET vNext Beta8 to issue and consume JWT tokens as described here.

In our implementation we're storing some client details in Redis at token issuing time and we would like the flush this information when the user logs out.

My question is what is the best practices for logging out with OIDC?

While I could roll my own contoller for this purpose I couldn't help but notice Open ID Connect (OIDC) seems somewhat primed to handle this case. For example OIDC has an OnLogoutEndpoint handler and LogoutEndpointPath settings. But when I call the OIDC logout URI that handler appears to accept any random x-www-form-urlencoded form I throw at it and doesn't in any particular way seem to be demanding the presence of a token.

Any advice on proper OIDC logout practices would be very much appreciated.

Tracheostomy answered 24/11, 2015 at 15:7 Comment(0)
C
1

In AspNet.Security.OpenIdConnect.Server, the logic used for the logout endpoint is left as an exercise.

In this sample, it is implemented using an MVC 6 controller, where you're - of course - free to add custom logic to remove cached details from your Redis server.

[HttpPost("~/connect/logout")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout() {
    // When invoked, the logout endpoint might receive an unauthenticated request if the server cookie has expired.
    // When the client application sends an id_token_hint parameter, the corresponding identity can be retrieved using AuthenticateAsync.
    var identity = await HttpContext.Authentication.AuthenticateAsync(OpenIdConnectServerDefaults.AuthenticationScheme);

    // Remove the cached details here. If you need to determine
    // who's the authenticated user, you can use the identity variable.

    // Remove the authentication cookie and return the user to the client application.
    return SignOut("ServerCookie", OpenIdConnectServerDefaults.AuthenticationScheme);
}

You can also do something similar directly from the LogoutEndpoint event. Don't forget to call context.HandleResponse() to make sure the request is not intercepted by another middleware.

Considerable answered 2/12, 2015 at 1:26 Comment(11)
thanks - just out of curiosity if I use the LogoutEndpoint event why is that endpoint event expecting a form, or more to the point, what is expected to be in that form?Tracheostomy
Using a POST request/form is not mandatory, you can also use a single GET request. I used a form here because I wanted to add anti-XSRF support to the logout endpoint, to prevent unwanted logout (the "superlogout" syndrome). Alternatively, you can also use id_token_hint for that: github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/…Flori
(FYI: starting with the next beta, we'll stop using JWT access tokens by default and go back to opaque tokens. See github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/… for more information)Flori
Ok, given that we're calling app.UseJwtBearerAuthentication will our OIDC implementation function as-is or will we need to turn some additional knobs to keep it working with JWT tokens?Tracheostomy
When migrating to beta5, your app will stop working if you don't fix it. Enabling JWT tokens will only require a line of code in the configuration delegate. That said, migrating to our new validation/introspection middleware will be the recommended approach.Flori
Great, thanks for the heads up. In the meantime another OIDC question for you here.Tracheostomy
Hey, @Pinpoint - I read your issue 99. Following the recommendation I can hook up to the LogoutEndpoint event, call GET/w an Authorization header and get the token via context.HttpContext.Authentication.AuthenticateAsync("Bearer"). I can also call it with a POST using a form and id_token_hint set to my base-64 encoded token (no authorization header) but then context.HttpContext.Authentication.AuthenticateAsync("Bearer") just returns null. Did I misinterpret what id_token_hint should be?Tracheostomy
Ah yeah, the scheme changed since the post was written. You now need to use the OpenIdConnectServerDefaults.AuthenticationScheme constant. Also note that you must use the id_token you received in the authorization/token response, not the access token.Flori
Ok now I understand - I should be supplying the id_token that was received in the authorization/token response. Curiously the response I am getting back from OIDC doesn't look like that, I only get back token_type, access_token and expires_in. I'm sure this is related to the OpenIdConnectServerDefaults.AuthenticationScheme you describe but not sure where to use it?Tracheostomy
Very unlikely. By default, the OIDC server will only return an identity token if you include "openid" in the scope parameter.Flori
Thanks, @Pinpoint - got it working on POST. For the benefit of anyone reading this: By including "openid" for the scope key when I request a token I receive back a response that includes the id_token. I can then call the logout endpoint from my endpoint, supplying the aforementioned id_token in the id_token_hint parameter of the logout form. In my LogoutEndpoint event handler I can get at my ID by calling var principal = await context.HttpContext.Authentication.AuthenticateAsync(OpenIdConnectServerDefaults.AuthenticationScheme), do the logout and then context.HandleResponse() at the end.Tracheostomy

© 2022 - 2024 — McMap. All rights reserved.