It’s often desirable for an Azure Active Directory (Azure AD)- integrated application to maintain application state when sending request to Azure AD for login. The recommended way to achieve this is to use the ‘state’ parameter as defined in the OpenID Connect standards. Also mentioned in our documentation, the ‘state’ parameter is used for both preventing cross-site request forgery attacks and to maintain user’s state before authentication request occurs:
For an ASP.NET or ASP.NET CORE web application using OpenID Connect OWIN middleware, the ‘state’ parameter is maintained automatically by the middleware when sending out an authentication request as followed.
&redirect_uri=<Some redirect URL>
Upon receiving the response from Azure AD, the middleware takes care of validating the ‘state’ parameter to prevent cross-site forgery attack. Because this work is done automatically by the middleware framework, this begs the question: How can application developers still utilize this same ‘state’ parameter to maintain user state without compromising the middleware’s security feature?
The way to do this is…
The OpenID Connect OWIN middleware use .Net framework’s Data Protection API to encrypt the value stored in the ‘state’ parameter. Thinking along the same line we can use the following code in OpenIdConnectNotifications’s RedirectToIdentityProvider event to inject custom data into the ‘state’ parameter:
var stateQueryString = notification.ProtocolMessage.State.Split('='); var protectedState = stateQueryString; var state = notification.Options.StateDataFormat.Unprotect(protectedState); state.Dictionary.Add("MyData", "123"); notification.ProtocolMessage.State = stateQueryString + "=" + notification.Options.StateDataFormat.Protect(state);
And we can use the following code to read our custom data back in the AuthenticationFailed event, MessageReceived event, or at any other relevant place in the code after we receive a response from Azure AD:
string mycustomparameter; var protectedState = notification.ProtocolMessage.State.Split('='); var state = notification.Options.StateDataFormat.Unprotect(protectedState); state.Dictionary.TryGetValue("MyData", out mycustomparameter);