2

I am trying to use Sitecore 10.0.1, IdentityServer4, with Okta and OpenID Connect. When I click logout I get this error:

{"errorCode":"invalid_client","errorSummary":"A client_id must be provided in the request.","errorLink":"invalid_client","errorId":"oaevKZNtJFrRjqTZ_wCOsx6lA","errorCauses":[]}

Here is the OnRedirectToIdentityProviderForSignOut code:

                options.Events.OnRedirectToIdentityProviderForSignOut += (Func<RedirectContext, Task>)(context =>
                {
                    context.Request.QueryString.Add("client_id", identityProvider.ClientId); // Did not fix issue
                    context.Options.ClientId = identityProvider.ClientId;  // Did not fix issue
                    context.Options.SignedOutRedirectUri = "https://id.myproject.localhost";
                    _logger.LogInformation("Redirect to identity provider for sign out. ClientId: {0}",
                        context?.Options?.ClientId);

                    context.ProtocolMessage.IdTokenHint = context.HttpContext.User.FindFirst("id_token")?.Value;  // This returns null
                    _logger.LogInformation("IdTokenHint: {0}", context.ProtocolMessage.IdTokenHint);

                    return Task.CompletedTask;
                });
                options.Events.OnRedirectToIdentityProvider += (Func<RedirectContext, Task>)(context =>
                {
                    _logger.LogInformation("Redirect to identity provider. IdToken: {0}.",
                        context.ProtocolMessage.IdToken);

                    var first = context.HttpContext.User.FindFirst("idp");
                    if (string.Equals(first?.Value, identityProvider.AuthenticationScheme, StringComparison.Ordinal))
                        context.ProtocolMessage.Prompt = "select_account";
                    return Task.CompletedTask;
                });

I was thinking this might be related to IdTokenHint but I don't seem to have that available.

4
  • 1
    Is this for the CM/Business users or the front website?
    – Julius A
    Commented Apr 26, 2021 at 20:14
  • Also, it may be helpful if you please share your code around how you are redirecting to the Identity provider. For example, how are you handling the OnRedirectToIdentityProvider event?
    – Julius A
    Commented Apr 26, 2021 at 20:32
  • This is for the CM/Business users Commented Apr 26, 2021 at 20:35
  • I added the OnRedirectToIdentityProvider to the post above. Commented Apr 26, 2021 at 20:37

4 Answers 4

1

I ran into the same issue and resolved it by storing the IdToken in a persistent storage so it can be retrieved later during logout. In our case it is in Redis and we used the same approach as my answer here, but this can obviously be different depending on your solution. I'm assuming you have access to IdToken in SecurityTokenValidated event?

3

In the AddOpenIdConnect function set options.SaveTokens = true; then you can retrieve the token in the OnRedirectToIdentityProviderForSignOut handler using the GetTokenAsync extension method from the Microsoft.AspNetCore.Authentication namespace.

options.Events.OnRedirectToIdentityProviderForSignOut += (Func<RedirectContext, Task>)(async context =>
{
   context.ProtocolMessage.IdTokenHint = await context.HttpContext.GetTokenAsync(OpenIdConnectResponseType.IdToken);
});
1
  • thanks, this works locally but fails in staging. May be due to strict policies in staging for saving tokens?
    – Neel
    Commented Dec 27, 2022 at 11:23
1

I have working code I have used with IdentityServer4 that I believe should work with Okta. The full solution is available on my repo here.

    public void ConfigureServices(IServiceCollection services)
    {
        Ids4DemoIdentityProvider identityProvider = this._appSettings.Ids4DemoIdentityProvider;
        if (!identityProvider.Enabled)
            return;
        this._logger.LogDebug("Configure '" + identityProvider.DisplayName + "'. AuthenticationScheme = " + identityProvider.AuthenticationScheme + ", ClientId = " + identityProvider.ClientId, Array.Empty<object>());
        new AuthenticationBuilder(services).AddOpenIdConnect(identityProvider.AuthenticationScheme, identityProvider.DisplayName, (Action<OpenIdConnectOptions>)(options =>
        {
            options.SignInScheme    = "idsrv.external";
            options.ClientId        = identityProvider.ClientId;
            options.Authority       = identityProvider.Authority;
            options.MetadataAddress = identityProvider.MetadataAddress;
            options.CallbackPath    = "/signin-idsrv";
            options.Events.OnRedirectToIdentityProvider += (Func<RedirectContext, Task>)(context =>
            {
                Claim first = context.HttpContext.User.FindFirst("idp");
                if (string.Equals(first != null ? first.Value : (string)null, identityProvider.AuthenticationScheme, StringComparison.Ordinal))
                    context.ProtocolMessage.Prompt = "select_account";
                return Task.CompletedTask;
            });
        }));
    }

I suggest you try with this and see if this resolves your issue

3
  • We found that the context.ProtocolMessage.IdTokenHint is not set on logout. But if we breakpoint / copy that value on login then breakpoint / pasted the value in logout it works. How can we persist that value for use in logout? Commented Apr 27, 2021 at 16:14
  • Did quick search and this might help you: Add id_token in list of claims in SecurityTokenValidated callback and used this in RedirectToIdentityProvider callback". Read more here: github.com/IdentityServer/IdentityServer3/issues/2334
    – Julius A
    Commented Apr 27, 2021 at 19:00
  • Another one of our developers found this: context.ProtocolMessage.IdTokenHint = await context.HttpContext.GetTokenAsync(OpenIdConnectResponseType.IdToken); Commented Apr 30, 2021 at 15:05
0

For me the solution was to set SignOutScheme in OpenIdConnectOptions of AddOpenIdConnect:

services.AddAuthentication()
    .AddOpenIdConnect(OpenIDConnectAuthenticationScheme, oidcOptions =>
    {
        oidcOptions.CallbackPath = "/signin-oidc";
        oidcOptions.SignedOutCallbackPath = "/signout-callback-oidc";
        oidcOptions.ResponseType = OpenIdConnectResponseType.Code;  //Code Flow
        oidcOptions.GetClaimsFromUserInfoEndpoint = true;
        oidcOptions.SaveTokens = true;
        oidcOptions.UseTokenLifetime = false;
        oidcOptions.ClaimActions.Add(new AspNetCore.Authentication.OAuth.Claims.MapAllClaimsAction());
        oidcOptions.SignOutScheme = OpenIDConnectAuthenticationScheme;  //<-- Important

        configuration.Bind($"Authentication:OpenIDConnect", oidcOptions);   //Sets Authority, ClientId and ClientSecret

        if (!(oidcOptions.Scope?.Any() ?? false))
        {
            //Add default scopes
            oidcOptions.Scope.Clear();
            oidcOptions.Scope.Add("openid");
            oidcOptions.Scope.Add("profile");
            oidcOptions.Scope.Add("email");
        }
    });

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.