Microsoft-authentication-library-for-dotnet: [Bug] Uno - Exchange authorization code for bearer token blocked by CORS in browser

Created on 5 Jun 2020  Â·  29Comments  Â·  Source: AzureAD/microsoft-authentication-library-for-dotnet

Which Version of MSAL are you using ?
4.14

Platform
WebAssembly

What authentication flow has the issue?

  • Desktop / Mobile

    • [ ] Interactive

    • [ ] Integrated Windows Auth

    • [ ] Username Password

    • [ ] Device code flow (browserless)

  • Web App

    • [ X ] Authorization code

    • [ ] OBO

  • Web API

    • [ ] OBO

Other? - please describe;

Is this a new or existing app?
This is a new app or experiment

Expected behavior
Successfully exchange authorization code for bearer token

Actual behavior
Exchange blocked by CORS

Additional context/ Logs / Screenshots
I'm using the Uno platform to write an Azure B2C authenticated multi-platform app using auth code flow via PublicClientApplication. While most of the heads (i.e. Android, UWP, etc) work fine using this approach, I'm hitting an issue with the web assembly (WASM) head.

In the WASM project I'm able to show the sign-in page and successfully sign-in, but then hit a CORS error ("Access to fetch at 'https://{TENANT}.b2clogin.com/tfp/{TENANT}.onmicrosoft.com/b2c_1_signupandsignin/oauth2/v2.0/token' from origin 'http://localhost:5000' has been blocked by CORS policy") when the PublicClientApplication endeavours to swap the authorization code for an access token.

Now given the WASM head is effectively a Single-Page Application, I tried following the instructions for Migrat[ing] a JavaScript single-page app from implicit grant to auth code flow. I added a new Application to my Azure B2C tenant and configured the "Single-page application" platform such that I now see the "Your Redirect URI is eligible for the Authorization Code Flow with PKCE." notice in the "Grant types" section. It is my understanding that this configuration enables CORS but, even after these changes, I still hit exactly the same CORS issue within my application.

Capturing the session during login reveals that, as per the CORS protocol, the browser is making an OPTIONS request to the token endpoint which is responding with a 404 thereby preventing the POST to the token endpoint for authorization code exchange.

Here's the session (with the Azure B2C Tenant replaced with '{TENANT}', tokens replaced with '{TOKEN}' and state replaced with '{STATE}'):

| Method | Url | Result |
| ------ | --- | ------ |
| GET | https://{TENANT}.b2clogin.com/tfp/{TENANT}.onmicrosoft.com/b2c_1_signupandsignin/oauth2/v2.0/authorize?scope=https%3A%2F%2F{TENANT}.onmicrosoft.com%2Fbackends%2Fread.only+offline_access+openid+profile&response_type=code&client_id=32bfdaf8-cc9f-4011-942d-851911aef544&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2Fauthentication%2Flogin-callback.htm&client-request-id=293915f0-a719-46a8-8003-bba230c4a49c&x-client-SKU=MSAL.UnoWasm&x-client-Ver=4.4.0.0&x-client-OS=web&prompt=select_account&code_challenge=mTjqNj7n3fMaon2_7HrIzpfGhwLPIwqrpMRCBt47-I4&code_challenge_method=S256&state={STATE} | 200 OK |
| POST | https://{TENANT}.b2clogin.com/{TENANT}.onmicrosoft.com/B2C_1_signupandsignin/SelfAsserted?tx=StateProperties={STATE}&p=B2C_1_signupandsignin | 200 OK |
| GET | https://{TENANT}.b2clogin.com/{TENANT}.onmicrosoft.com/B2C_1_signupandsignin/api/CombinedSigninAndSignup/confirmed?csrf_token={TOKEN}&tx=StateProperties={STATE}&p=B2C_1_signupandsignin&diags=%7B%22pageViewId%22%3A%228a316cef-e06e-42c2-97a8-9dc9cfcd5d5a%22%2C%22pageId%22%3A%22CombinedSigninAndSignup%22%2C%22trace%22%3A%5B%7B%22ac%22%3A%22T005%22%2C%22acST%22%3A1591363250%2C%22acD%22%3A2%7D%2C%7B%22ac%22%3A%22T021%20-%20URL%3Ahttps%3A%2F%2F{TENANT}.b2clogin.com%2Fstatic%2Ftenant%2Ftemplates%2FAzureBlue%2Funified.cshtml%3Fslice%3D001-000%26dc%3DDB3%22%2C%22acST%22%3A1591363250%2C%22acD%22%3A55%7D%2C%7B%22ac%22%3A%22T029%22%2C%22acST%22%3A1591363250%2C%22acD%22%3A13%7D%2C%7B%22ac%22%3A%22T004%22%2C%22acST%22%3A1591363250%2C%22acD%22%3A3%7D%2C%7B%22ac%22%3A%22T019%22%2C%22acST%22%3A1591363250%2C%22acD%22%3A25%7D%2C%7B%22ac%22%3A%22T003%22%2C%22acST%22%3A1591363250%2C%22acD%22%3A52%7D%2C%7B%22ac%22%3A%22T002%22%2C%22acST%22%3A0%2C%22acD%22%3A0%7D%5D%7D | 302 Found |
| GET | http://localhost:5000/authentication/login-callback.htm?state={STATE}&code={TOKEN} | 200 OK |
| OPTIONS | https://{TENANT}.b2clogin.com/tfp/{TENANT}.onmicrosoft.com/b2c_1_signupandsignin/oauth2/v2.0/token | 404 Not Found |

I believe this is likely to be an issue with the Azure B2C service (and I will report an issue to them as soon as I can find an appropriate forum) but was wondering if the above flow looks correct to you?

Thanks,
Ian

B2C external

Most helpful comment

Just had an update from the Azure AD B2C team: A fix for this issue will be deployed on the 21st August.

Fingers crossed it correctly implements the CORS protocol. I'll test as soon as the fix has been deployed and update this issue accordingly.

All 29 comments

@jmprieur for guidance for Blazor.

MSAL.NET does not support implicit flow / running from browser, but MSAL.js does ... https://github.com/AzureAD/microsoft-authentication-library-for-js

@bgavrilMS, yes, I thought that might be the response. From what I can see MSAL.js v2 has added (almost) the exact same PublicClientApplication approach as is used in MSAL.NET. Given the approach is _so close_ to working as is, I was kinda hoping someone could weigh in on whether this is (an unsupported) issue in MSAL.NET or if there's an issue with Azure B2C (who's "Single-page application" platform seems very new).

Could you describe in more detail how you got MSAL.NET to show you the login form in WebAssembly? MSAL.NET has 2 options for showing a browser when using the Authorization flow via PublicClientApplication (i.e. AcquireTokenInteractive)

  • embedded browser (a good old WinForms panel hosting a WebBroswer control)
  • system browser (i.e. start a new process, similar to start https:\\www.login.mso.com\authorize... )

I use Uno.Microsoft.Identity.Client in the webassembly project. It is "a fork of MSAL.NET - Microsoft.Identity.Client to support Uno-WASM target" and basically adds a new IWebUI implementation that is able to interact with the browser via JS interop. Code can be found here.

@ibebbs @bgavrilMS
would it make sense to contribute back to the main MSAL.NET ?

@jmprieur Yes it does make sense to contribute back soon. We've considered it and until we can get the integration to work properly from many scenarios, we'll keep it separate. The biggest constraint here is the fact that Uno for WebAssembly uses netstandard2.0 as the TFM which could create some conflicts and misunderstandings. This is a complex discussion wrt. Blazor, and Uno support for WebAssembly where such a platform cannot be discriminated easily by NuGet.

@carldebilly will be able to comment more, but the best way for the WebAssembly support for Uno to be available would be to allow for external packages to provide implementation for specific internal classes of MSAL.NET. That would avoid to have to alter the behavior of the netstandard2.0 TargetFramework in the main MSAL.NET package, and allow for platform or environment specific overrides defined by an additional package.

Note that you don't necessarily need to fork MSAL just for a custom implementation of IWebUi, we have exposed an extensibility point just for that called ICustomWebUi

I'm afarid I don't know much about the CORS issue, perhaps @jasonnutter from MSAL.js can advise ?

@jmprieur, I would be more than happy to create a PR to merge back Uno support into MSAL.NET instead of having to maintain it on our side for each releases.

@bgavrilMS: adding support for Uno-Wasm is more than just implementing a browser... it's actually creating a new platform: https://github.com/unoplatform/Uno.Microsoft.Identity.Client/blob/master/src/client/Microsoft.Identity.Client/PlatformsCommon/Factories/PlatformProxyFactory.cs#L37_L39.

As @jeromelaban said, I think the best approach would be to find a way to inject the "proxy factory" at runtime using a kind of abstract factory pattern.

Now given the WASM head is effectively a Single-Page Application, I tried following the instructions for Migrat[ing] a JavaScript single-page app from implicit grant to auth code flow. I added a new Application to my Azure B2C tenant and configured the "Single-page application" platform such that I now see the "Your Redirect URI is eligible for the Authorization Code Flow with PKCE." notice in the "Grant types" section. It is my understanding that this configuration enables CORS but, even after these changes, I still hit exactly the same CORS issue within my application.

Capturing the session during login reveals that, as per the CORS protocol, the browser is making an OPTIONS request to the token endpoint which is responding with a 404 thereby preventing the POST to the token endpoint for authorization code exchange.

@pkanher617 Have you heard about the OPTIONS request for B2C 404ing?

Update to my previous comment: I confirm it works by using the netstandard1.3 version of MSAL.NET. I implemented both ICustomWebUi and IMsalHttpClientFactory and I succeed to use Microsoft.Identity.Client package (minor a problem with ref assemblies caused by the Uno Bootstrapper).

It think it's a viable solution better than the fork. I'll continue to investigate it.

Am going to close this, please reopen or open a new issue as needed.

@bgavrilMS, is closing this issue the right course of action right now? I understand that its not an issue with MSAL.NET _specifically_ but it is an error that is still being investigated by the Azure AD B2C team.

Closing this issue may make it seem like this issue has been resolved when it, at the current time, it hasn't.

Reopening as per @ibebbs 's request. It's not clear from this thread that someone from B2C team is looking at this, I hope they are.

Thanks @bgavrilMS , yes they are looking at this. I have an open support request with them and they have confirmed the issue.

I'm not sure how best to keep this issue up to date with the support request other than updating it manually.

Any suggestions?

No suggestion, I think updating it manually is the only way to go.

You can add a link to the support case here, even if only @microsoft accounts can access it, so that we can check the progress. We tend to look over open issues that haven/t been actioned in a while and close them, so this will help see progress.

Sorry @bgavrilMS , I've looked but can't find any form of link for the support request in the Azure "Help + Support" blade so don't think I'm able to share a link.

If you know how, let me know and I'll try to provide one.

Hi @bgavrilMS ,

Any idea why this issue has been marked as "done" on the project board? It's still very much not done I'm afraid.

By way of an update, the Azure AD B2C team did release a fix for the OPTIONS issue such that it now responds to the call. Unfortunately, it does not respond _correctly_! The response to the OPTIONS call does not include the 'Access-Control-Allow-Origin' header required to allow the CORS operation to proceed.

When I reported this to the B2C team (on 20 July) they responded with:

It looks like we're aware of this new issue--it's impacting MSAL 2.0 applications that are trying to connect to B2C, it is not impacting only you. We’re actively working on a code fix on the B2C side to address this issue. It looks like MSAL 2.0 (used by this application) doesn't have B2C support yet (b/c of this issue).

I received a further update 2 days later stating:

I’ve managed to gather more information for you as it seems we have multiple customers affected by this with the same request for us.
We are working on a fix for it.
However, this is a change that needs to be done on the B2C side, and it is not a small fix. Therefore I want to set your expectations correctly: The fix will not be finalized this month, therefore we’re looking at a release sometime in August if everything goes as planned.

Furthermore they point out that they have now updated the about page of "Microsoft Authentication Library for JavaScript (MSAL.js) 2.0 for Browser-Based Single-Page Applications" to state that:

Important: MSAL.js 2.0 with Authorization Code Flow is not yet available for B2C tenants (coming soon).

So, there we have it. The allegedly "supported" flow isn't actually supported but they're "working on it". All very disappointing really.

I'm not sure how you want to proceed with this issue here but I am concerned that marking this issue as "done" might give an incorrect impression that this is working.

I'm not sure what we can do here as we do not own Uno's fork of MSAL, nor do we own MSAL js. It looks like you've successfully engaged with the B2C server team and with the MSAL js team.

@bgavrilMS There's is no fork of MSAL on Uno. We're simply pushing a custom implementations of ICustomWebUi and IMsalHttpClientFactory.

Uno is using the unforked version of MSAL dotnet (not MSAL.js) running using .NETStandard 1.3 on mono-wasm in a browser.

Hi @bgavrilMS, I understand your sentiment here: This is very much an issue with Azure AD B2C not with the MSAL.net library.

Blocked sounds like an apprioriate status but if you would prefer to close this for reasons of getting it off the project board, that would be understandable.

If you do decide to leave this issue open, I will be sure to update it when I receive further information from the Azure AD B2C team.

Either way, totally your call.

Just had an update from the Azure AD B2C team: A fix for this issue will be deployed on the 21st August.

Fingers crossed it correctly implements the CORS protocol. I'll test as soon as the fix has been deployed and update this issue accordingly.

Hi Ian

I just retried with my code and I still get a CORS error from the token request.

However, it may just be my code: Is it working for you?

Regards
Ed

From: Ian Bebbington
Sent: 07 August 2020 09:23
To: AzureAD/microsoft-authentication-library-for-dotnet
Cc: EdBlacker; Manual
Subject: Re: [AzureAD/microsoft-authentication-library-for-dotnet] [Bug] Uno -Exchange authorization code for bearer token blocked by CORS in browser(#1865)

Just had an update from the Azure AD B2C team: A fix for this issue will be deployed on the 21st August.
Fingers crossed it correctly implements the CORS protocol. I'll test as soon as the fix has been deployed and update this issue accordingly.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or unsubscribe.

Hi Ed,

I haven't had an update from the AAD B2C team so I hadn't bothered testing the endpoint yet. I'll give them a poke and see where they're at then get back to you.

Cheers,
Ian

Sounds good – thanks for the efforts, and keeping me in the loop.

Cheers
Ed

From: Ian Bebbington
Sent: 24 August 2020 22:04
To: AzureAD/microsoft-authentication-library-for-dotnet
Cc: EdBlacker; Manual
Subject: Re: [AzureAD/microsoft-authentication-library-for-dotnet] [Bug] Uno -Exchange authorization code for bearer token blocked by CORS in browser(#1865)

Hi Ed,
I haven't had an update from the AAD B2C team so I hadn't bothered testing the endpoint yet. I'll give them a poke and see where they're at then get back to you.
Cheers,
Ian
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or unsubscribe.

Latest from the AAD B2C team:

It looks like the engineering team ran into some delays, the new ETA is the 28th of August, is in 3 days.

Given there has been no update from the Azure AD B2C team, I tested this issue this morning and can confirm it still exists.

I have asked for an updated ETA...

@EdBlacker, the Azure AD B2C team deployed a fix for this issue on Friday. I ran some preliminary tests and it seems to work.

@bgavrilMS, unless @EdBlacker encounters further problems, I believe this issue can be closed now. Thanks for keeping it active while the issue was addressed.

Thanks for the update, @ibebbs!

@ibebbs @jmprieur I confirm that it's working for me - thanks all!

Was this page helpful?
0 / 5 - 0 ratings