Identityserver4: 400 Bad Request (Invalid ID Token) on OIDC logout with Okta

Created on 1 May 2018  路  6Comments  路  Source: IdentityServer/IdentityServer4

Issue / Steps to reproduce the problem

I am using a largely unmodified version of QuickStart 7 (Javascript Client). The only modification is to change the OIDC Authority and ClientId. I have also separated the JS Client and the ID Server into two separate solutions for my own convenience/taste. I am not running the protected API because it is not relevant to this problem (though it works perfectly).

Login runs perfectly:
I run both the ID Server and the JS Client in debuggers.
I connect to the JS Client (http://localhost:5003) (Chrome, Firefox, and Edge all perform correctly)
I click "Login"
Login page appears. Click "OpenID Connect" button
Login flow continues. Click Allow button
Login flow concludes. Token data is displayed on http://localhost:5003/index.html

Logout, however, is where the issue arises (Below is the redirect flow)
Click Logout button

  1. (Response 302) http://localhost:5000/endsession?id_token_hint=###&post_logout_redirect_uri=http://localhost:5003/index.html
  2. (Response 302) http://localhost:5000/logout?logoutid=###
  3. (Response 400) https://myurl.okta.com/oauth2/v1/logout?post_logout_redirect_uri=http://localhost:5000/signout-callback-oidc&state=###&x-client-SKU=ID_NET&x-client-ver=2.1.4.0

As you can see, above, there is no id_token_hint being sent to the Okta server and thus the request is being rejected.

During the login process, I can see something called "id_token" being returned from Okta, then being POSTed to signin-oidc just before the browser is redirected to ExternalLoginCallback (where my code would have an opportunity to perform work). But I cannot find that id_token, nor any property called a "hint". Debugging the controller demonstrates that the following code does not yield an id token, even though it appears that it was, in fact, returned by the Okta server:

// if the external provider issued an id_token, we'll keep it for signout
AuthenticationProperties props = null;
var id_token = result.Properties.GetTokenValue("id_token");
if (id_token != null) _//// id_token is null here_
{
props = new AuthenticationProperties();
props.StoreTokens(new[] { new AuthenticationToken { Name = "id_token", Value = id_token } });
}

result.Properties contains the following key/value pairs:
.AuthScheme: oidc
returnUrl: /connect/authorize/callback?client_id=js&redirect_uri=http://localhost:5003/callback.html&response_type=id_token token&scope=openid profile api1&state=###&nonce=###
scheme: oidc
.issued: Tue, 01 May 2018 13:13:55 GMT
OpenIdConnect.Code.RedirectUri: http://localhost:5000/signin-oidc
.expires: Tue, 15 May 2018 13:13:55 GMT

If I modify my Startup.cs such that I set the options.Events property and set the OnTokenValidated property to an appropriate method, I can see the id_token in arg.Request.Form["id_token"]. However, I simply do not know what to do with it at this point.

Any assistance in determining how to properly log out of Okta using the OIDC workflow would be very much appreciated.

Relevant parts of the log file

I am uncertain what logging would be relevant to the issue at this time. I do not see anything suggesting that an exception is being thrown or that there is erroneous data in the flow.

question

Most helpful comment

I read into the Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler class. Specifically, the SignOutAsync(AuthenticationProperties) method. There is a line within (#195):

// Attach the identity token to the logout request when possible.
message.IdTokenHint = await Context.GetTokenAsync(Options.SignOutScheme, OpenIdConnectParameterNames.IdToken);

the "message" variable above is an instance of OpenIdConnectMessage

This appears to be the only place where IdTokenHint is assigned. And, by all appearances, id_token is not on the Context that it is trying to access.

However, in my Startup.cs file, I was able to add an event handler to the OpenIdConnectEvents object.

OnRedirectToIdentityProviderForSignOut

The HttpContext on the RedirectContext DOES have the id_token, and assigning that to redirectContextInstance.ProtocolMessage.IdTokenHint allowed it to flow through to the call to Okta, and I was successfully logged out of my Okta context, as well. Huzzah!

All 6 comments

Your app's integration between Okta is beyond what we're able to support here. I'd suggest getting a stand alone asp.net core app working with Okta the way you want (including signout), then merge that into your IdentityServer host.

Bummer. Fair enough, though. Thanks!

For the sake of hoping that someone else will see this and possibly comment on my plight, I will continue the discussion as I find interesting things (perhaps I'll even find a resolution).

So I discovered why the id_token wasn't being found - I need to set OpenIdConnectOptions.SaveTokens = true. Suddenly, the id_token appears and it gets saved.

Is there, perhaps, another setting, somewhere, that will allow that id_token to be pulled from storage and added to the Okta call? Continuing to search...

I read into the Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler class. Specifically, the SignOutAsync(AuthenticationProperties) method. There is a line within (#195):

// Attach the identity token to the logout request when possible.
message.IdTokenHint = await Context.GetTokenAsync(Options.SignOutScheme, OpenIdConnectParameterNames.IdToken);

the "message" variable above is an instance of OpenIdConnectMessage

This appears to be the only place where IdTokenHint is assigned. And, by all appearances, id_token is not on the Context that it is trying to access.

However, in my Startup.cs file, I was able to add an event handler to the OpenIdConnectEvents object.

OnRedirectToIdentityProviderForSignOut

The HttpContext on the RedirectContext DOES have the id_token, and assigning that to redirectContextInstance.ProtocolMessage.IdTokenHint allowed it to flow through to the call to Okta, and I was successfully logged out of my Okta context, as well. Huzzah!

Hello @lassanter,

Thank you for your comment. Currently I am facing same issue but not able to add the code in my app.
My question is : where should I put this code - in startup.cs or AuthenticationController.cs?
Please forgive for my naiveness, I am new to .Net, C#.

If it is possible for you, can you please post the code block? It would be very helpful for me.
Thank you so much.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

eshorgan picture eshorgan  路  3Comments

wangkanai picture wangkanai  路  3Comments

user1336 picture user1336  路  3Comments

garymacpherson picture garymacpherson  路  3Comments

osudude picture osudude  路  3Comments