Why do you need to pass the query string to the external login provider? Is it because after login or logout you need that value back in Sitecore? If that's the case you could also add the value to the state.
Here is an example where I add the Nonce value to the state during logout:
public Task RedirectToIdentityProviderAsync(
RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>
notification)
{
var domain = this.urlUtils.GetDomain();
var owinContext = notification.OwinContext;
var protocolMessage = notification.ProtocolMessage;
if (protocolMessage.RequestType == OpenIdConnectRequestType.Logout)
{
var postLogoutRedirectUri = this.configurationRepository.GetSetting(OpenIdConnectOptions.PostLogoutRedirectUri);
postLogoutRedirectUri = WebUtil.GetUri(postLogoutRedirectUri, new Uri(domain)).ToString();
protocolMessage.PostLogoutRedirectUri = postLogoutRedirectUri;
protocolMessage.IdTokenHint = this.GetIdTokenHint(owinContext);
if (!notification.OwinContext.Authentication.AuthenticationResponseRevoke.Properties.Dictionary.TryGetValue(OpenIdConnect.Nonce, out var nonce))
{
throw new InvalidOperationException(this.GetType().FullName + ".AddNonceToState: unable to find 'nonce' value in the owinContext.Authentication.AuthenticationResponseRevoke.Properties.");
}
// The nonce value is used to associate a Client session with an ID Token, and to mitigate replay attacks.
// Adding the nonce to the state is the only option the identity provider supports.
AddToState(notification, OpenIdConnect.Nonce, nonce);
}
return Task.CompletedTask;
}
private void AddToState(RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification, string name, string value)
{
var state = new AuthenticationProperties();
var stateName = OpenIdConnect.AuthenticationProperties;
if (!string.IsNullOrEmpty(notification.ProtocolMessage.State))
{
var stateQueryString = notification.ProtocolMessage.State.Split('=');
if (stateQueryString.Length >= 2)
{
stateName = stateQueryString[0];
var protectedState = stateQueryString[1];
state = this.dataProtector.UnprotectPropertiesWithOwinDataProtector(notification.Options.StateDataFormat, protectedState);
}
}
state.Dictionary.Add(name, value);
notification.ProtocolMessage.State = stateName + "=" + this.dataProtector.ProtectPropertiesWithOwinDataProtector(notification.Options.StateDataFormat, state);
}
Once you are logged out on the identity provider you get redircted back to Sitecore. There you can access the state again:
private void UnRegisterExternalLogout(IOwinContext context, IAppBuilder app)
{
var state = context.Request.Query.Get(OpenIdConnect.State);
var stateQueryString = state.Split('=');
if (stateQueryString.Length >= 2 && stateQueryString[0] == OpenIdConnect.AuthenticationProperties)
{
// Get the state and unprotect it.
var protectedState = stateQueryString[1];
var authenticationProperties = this.dataProtector.UnprotectPropertiesWithOwinDataProtector(
app,
typeof(OpenIdConnectAuthenticationMiddleware).FullName,
OpenIdConnect.EnexisIdentityProvider,
OpenIdConnect.Version,
protectedState);
// Get the nonce value from the state and validate it.
authenticationProperties.Dictionary.TryGetValue(OpenIdConnect.Nonce, out var nonce);
if (this.IsValidUnRegisterExternalLogoutRequest(nonce, context))
{
// Delete the cookie which triggers the redirect to the external identity provider.
// If this doesn't get deleted it will create a redirect loop. If everything is valid that will never happen.
context.Response.Cookies.Delete(Sitecore.Owin.Authentication.Constants.ExternalLogOutCookieName, new CookieOptions()
{
HttpOnly = true,
Path = "/"
});
}
}
}
So in the above code we send a nonce value in the state and read that value again once we get back to Sitecore.