React v16.13.1
I'm using B2C and seeing the following browser error when redirecting from Custom policy B2C_1A_signup_invitation:
Browser error: AuthError: Unexpected error in authentication.: Hash does not contain state
Custom policy SignUpInvitation.xml here
Perhaps same as this closed issue here
Using wrapper syncweek-react-aad/react-aad

To redirect to a SPA application using react-aad-msal and msal
Error occurs on both Google Chrome 81 and Firefox
@stephenstroud Could you confirm with Fiddler or another network trace whether the state value is being returned in the call?
@pkanher617
Are you referring to the state property within the header? See below?

Redirect URL appears as https://localhost:3000/#id_token=sometoken
Error message appears like:

I tried out the basic sign in flow and I see a URL is called with a query string containing state=sometoken. However, I don't see this behaviour with the custom policy.
No the state parameter should come back in the hash along with the id_token, it doesn't appear to be working this way for this specific policy. I have a meeting with some B2C team members tomorrow, I will update when I have more info on a way forward.
Is it possible to enable this manually within the custom policy XML? i.e. can I add a setting to trigger this?
@pkanher617 this is happening on the standard signin/signup form - when redirecting from the signup form to the SPA I get the above error. Perhaps it's not specific to that template and something I've misconfigured within the B2C portal?
I'm also getting an intermittent HTTP ERROR 431 within Google Chrome. I haven't done anything fancy with the login form other than HTML/CSS styling.
@pkanher617 , @stephenstroud , we are experiencing the same with React and the Custom SignUp policy mentioned.
@pkanher617 @stephenstroud, @NathanJonker I am having the same issue using ReactJS and a custom sign up policy. It's worth mentioning, that it only occurs when creating a user. Both signing in/out and resetting password work fine.
@michalk93 Same case as me.
@stephenstroud I had the same issue with an invitation policy that signs up a user. As the error says, there is no "state"-parameter in the callback query string.
So I found a simple workaround, I don't know if this is a "best practice", but it works and it麓s based on WingTipGames-example, written in .NET.
Instead of sending the user directly to b2c signup page in the invitation-link, send them to your app, and redirect with the token from your app to b2c. In that way your app sends the state, and the b2c response callback gets back with a state parameter.
@hectorromo thanks for this workaround, this option does create some limitation to the invitation flow based on certain use cases such as having unique link that only exposes the registration form to those who have the link rather than a generalised link, however, some of this could be handled back in the SPA app.
Further to this, the "Run User Flow" function within Azure B2C dashboard will remain broken for user creation and will require to test locally - not that this is a real problem for us give we know the issue but will throw other new B2C developers off.
Hi all, thanks for your patience, this was identified as an issue with the B2C service. Please file a support ticket with the B2C team by following the instructions here: https://docs.microsoft.com/en-us/azure/active-directory-b2c/support-options
They can help you out further, they may ask for a public repro link or additional data. You can also link this Github issue in the support request.
Hey, I am facing same problem while sign-in through email , I get error Hash does not contain state
I followed this policies sample.
https://github.com/azure-ad-b2c/samples/tree/master/policies/sign-in-with-email/source-code.
When I point redirect-uri to https://www.jwt.ms, i get the expected claims. but when the redirect-uri points to react application(msal-implemented), it shows the error msg.
Has someone got the workaround for it.
@ChiragRatra-0009 I raised this with the Azure team after wasting hours trying to figure out the problem. Their response:
"The feedback received is that MSAL requires a "state" param that matches a cached value for browser-based apps (SPAs). This state param identifies the request and determines the original token time and is used to prevent cross-site request forgery attacks. Because of this, for SPAs, the email link should direct the user to the app, which can then redirect the user to the Azure AD B2C authentication flow. You can use query parameters in the email to app link so that your app can initiate the correct azure ad b2c authentication flow. E.g. pass the id_token_hint to your app then your app to the authentication flow. To summarize, email => app => authentication flow => app"
@ChiragRatra-0009 I raised this with the Azure team after wasting hours trying to figure out the problem. Their response:
"The feedback received is that MSAL requires a "state" param that matches a cached value for browser-based apps (SPAs). This state param identifies the request and determines the original token time and is used to prevent cross-site request forgery attacks. Because of this, for SPAs, the email link should direct the user to the app, which can then redirect the user to the Azure AD B2C authentication flow. You can use query parameters in the email to app link so that your app can initiate the correct azure ad b2c authentication flow. E.g. pass the id_token_hint to your app then your app to the authentication flow. To summarize, email => app => authentication flow => app"
Hey @stephenstroud , I really appreciate your inputs. Thanks.
I got the understanding of flow you suggested. But I am actually having problem configuring js code for sending id_token_hint to adb2c for authentication . It would be great if you could share some sample code.
@ChiragRatra-0009 I'm building this out next, You should receive the id_token_hint from the server side then build out the link client-side which is shown here
If you have multiple policies you could add a param in the query string indicating which flow it is then build your link based on that.
Once you have built the link, send them to it. The rest of the ADB2C flow should kick in.
Just make sure they hit your SPA first like this flow:
email invite => app(redirect link with id_token_hint) => authentication flow => app
@ChiragRatra-0009 I'm building this out next, You should receive the id_token_hint from the server side then build out the link client-side which is shown here
If you have multiple policies you could add a param in the query string indicating which flow it is then build your link based on that.
Once you have built the link, send them to it. The rest of the ADB2C flow should kick in.
Just make sure they hit your SPA first like this flow:
email invite => app(redirect link with id_token_hint) => authentication flow => app
Hi @stephenstroud
Thanks for the input, I followed the same flow as mentioned but I am still getting the error saying Hash does not contain state. So I am sharing the code , I think that would be provide you better insight of my work and hope you could figure out where the code has the difference than what you suggested
Backend Code (C# contains -> BuildToken and BuildUrl Method)
backendcode.txt
Frontend Code( React js signin contains -> function to geneate singin url and the method call when the application is loaded)
frontend.txt
Thanks in advance.
@ChiragRatra-0009 Does the return URL have an error description param indicting the issue?
@ChiragRatra-0009 Does the return URL have an error description param indicting the issue?
@stephenstroud no, I am getting the id_token. but when I intialise the msal instance then it shows the hash error
We're experiencing the same issue. It appears the URL with the id_token is missing the state param. The state param should be automatically appended from MSAL from my understanding. Looking at your frontend code have you initialised the MSAL object soon enough?
@stephenstroud , we initialise the msal instance after we recieve id_token as param in url.
Here is the samplecode.
But again mentioning the same I intialise the msal instance then it shows the hash error
Hey @tnorling @stephenstroud , have you guys found working solution for these policies ? I have been trying but still "NO".
@ChiragRatra-0009 The root of this problem is that Msal appends certain information such as state to the request url and sets some temporary cache values used to verify the response. Due to this it expects that the /authorize request originated from msal, if it originated from somewhere else, such as an invite link, you will receive an error because the setup steps were not done. The way around this is to make the invite link point to your app and have your app include the required query parameters (such as id_token_hint) in extraQueryParameters on the msal request object.
One of the first thing Msal does when it initializes is looks for known properties in the hash of the url. If it contains some known properties but not all (such as state), you will receive an error. If you look at the /authorize request in your developer tools and you determine it contains the state property in the url but the response no longer contains that state, it's a service issue. You can reach out to B2C support and they can help you figure out what's going on. If the state is not included in the /authorize request double check that the request originated from Msal and if it is, please open a new bug so we can investigate.
@ChiragRatra-0009 Extract the IdTokenHint and pass into the AuthenticationParameters object. This should get you going.
const someExtraQueryParameters = {
id_token_hint: idTokenHint,
};
const authParams: AuthenticationParameters = {
authority,
scopes,
someExtraQueryParameters ,
};
authProvider.loginRedirect(authParams);
@stephenstroud @tnorling guys the way you explained things its really awesome. So just last query here , after sending the id_token_hint in extraquery parameter in authentication request what result could I expect , will it be id_token in query string or will it store the access_token in the session storage?
Thanks in advance.
@ChiragRatra-0009 Extract the IdTokenHint and pass into the AuthenticationParameters object. This should get you going.
const someExtraQueryParameters = { id_token_hint: idTokenHint, }; const authParams: AuthenticationParameters = { authority, scopes, someExtraQueryParameters , }; authProvider.loginRedirect(authParams);
Hi everyone,
I have the same issue and I haven't understood your workaround, could you explain to me with a better example?
Thank you in advance,
@ChiragRatra-0009 I'm using a React wrapper here which stores the access_token to localstorage.
@moialbla There are a couple of parts of this to understand - this flow needs to be followed: invite => app => ADB2C => app
When triggering the invite, the user should be sent directly to your app with some query parameters. The params should include id_token_hint. Your app will have a custom method that intercepts the query params and then constructs the ExtraQueryParameters argument that is passed to a MSAL authprovider instance. The authprovider instance then constructs the redirect and appends the missing state param to the redirect for you. If you're using ADB2C and configured with your policy correct then ADB2C will handle the rest for you and redirect back to your app where a access_token might be passed.
@ChiragRatra-0009 Extract the IdTokenHint and pass into the AuthenticationParameters object. This should get you going.
const someExtraQueryParameters = { id_token_hint: idTokenHint, }; const authParams: AuthenticationParameters = { authority, scopes, someExtraQueryParameters , }; authProvider.loginRedirect(authParams);Hi everyone,
I have the same issue and I haven't understood your workaround, could you explain to me with a better example?
Thank you in advance,
Hi everyone,
I found a solution, maybe not the best solution, but it works. I've forced the login reload when the library throws an exception.
Below the code:
`const config = { ..... msalConfig };
let authAgent: Msal.UserAgentApplication;
initAuthorization () {
try {
authAgent = new Msal.UserAgentApplication(config );
//creates you own msal authcallback.
authAgent.handleRedirectCallback(authCallback);
} catch (e) {
//Of fails, the code redirect to your own page with the error param
if (e.message.indexOf("Hash does not contain state") > -1) {
window.location.href = window.location.origin + "?loginError=true";
}
//if it failed, the property state would be removed and it will go to this line. after that we will see the b2c redei
if (window.location.search === '?loginError=true') {
initAuthAgent();
authAgent.loginRedirect(authConfig);
}
}
};
I hope this helps someone.