Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] [L] Support PKCE (code_verifier) during confidential client auth code grant flows #1473

Closed
2 tasks
mattvperry opened this issue Oct 24, 2019 · 40 comments

Comments

@mattvperry
Copy link

mattvperry commented Oct 24, 2019

Is your feature request related to a problem? Please describe.
MSAL.NET supports PKCE for public client application (interactive flows). However, PKCE seems to have started becoming more commonly used for auth code flows outside of native/public clients. For example, aspnetcore 3.0 has included a "UsePKCE" flag to the OpenIdConnect middleware which adds the code_verifier to its built-in auth code redemption. The problem arises when you want to use MSAL to do the code redemption because there is no way to supply the code_verifier parameter to the auth code request.

Describe the solution you'd like
I believe the auth code request builder on the ConfidentialClientApplication should be expanded to allow custom code_verifier values to be supplied.

It might also be worth investigating whether MSAL should expose some mechanism for generating the code_verifier / code_challenge / code_challenge_method values as well instead of either:

  1. Implementing it yourself
  2. Letting aspnetcore's middleware generate it and then fish out their value from the AuthorizationCodeReceivedContext

Describe alternatives you've considered
I've looked through both MSAL's code and ADAL's code for any sneaky way in which to inject a custom body parameter value into the auth code request but have had no such success. For most use cases, aspnetcore's built-in auth code redemption isn't sufficient because it won't cache the tokens at all.

Steps:

  • Add new api to accept code verifier for PKCE in AcquireTokenByAuthorizationCode()
  • Add auth code + PKCE to confidential clients
@bgavrilMS
Copy link
Member

There are 2 points here: PKCE for aspnetcore 3.0 and adding an extra extensibility point "WithTokenRequestParamters", which would provide a gap solution until we have time to address the main scenario.

@jmprieur
Copy link
Contributor

jmprieur commented Oct 29, 2019

Another possibilty would be to let ASP.NET core get a refresh token (offline_access scope), and then get an access token from the refresh token with MSAL.NET AcquireTokenByRefreshToken. I'm not sure how good it is from a security point of view. @yordan-msft : what would be your recommendation?
cc: @bgavrilMS @henrik-me @jennyf19

@DieselSoup
Copy link

Has there been any progress on this issue? Have not tried either of the workarounds yet.

@henrik-me
Copy link
Contributor

@DieselSoup : This is not something we have been able to prioritize yet. Also we don't have an ETA yet. Not sure if we will be able to pick this up until next year.

@bgavrilMS
Copy link
Member

@henrik-me @jmprieur - there are more customers complaining about this. We should consider adding the extensibility mechanism that allows to us to send paramters to both /authroize and /token endpoints - and then Microsoft.Identity.Web can do some magic.

@jmprieur jmprieur added this to the 4.9 milestone Dec 19, 2019
@jmprieur jmprieur self-assigned this Dec 19, 2019
@jmprieur
Copy link
Contributor

@jmprieur to spec. Maybe half of the work in MS.Id.Web?

@jennyf19 jennyf19 modified the milestones: 4.9, 4.10 Feb 1, 2020
@vipulkelkar
Copy link

vipulkelkar commented Apr 6, 2020

I am trying to achieve a similar thing. Using code_verifier in confidential client. The open id connect options allow us to handle options.Events.OnAuthorizationCodeReceived within which I have extracted the code verifier sent to get auth code

context.TokenEndpointRequest.Parameters.TryGetValue("code_verifier", out var cv);

and then acquire a access token for custom web api by calling the token endpoint instead of using the ConfidentialClient. I get the access,refresh and Id token however I end up with "Unable to validate the 'id_token', no suitable ISecurityTokenValidator was found for: ''."" error. Any pointers ? The response type is "code". I am not using hybrid flow.

@jmprieur
Copy link
Contributor

This is now spec-ed (see Jenny's work in the MIcrosoft.Identtiy.Web issue). We just need to add an extra parameters for the code verifier which will be provided by ASP.NET Core.

Remains to prioritize
(before .NET 6)

@jmprieur
Copy link
Contributor

See also https://identitydivision.visualstudio.com/Engineering/_workitems/edit/1323064

@bgavrilMS
Copy link
Member

bgavrilMS commented Mar 18, 2021

Should be trivial to add an extra param to the public API. See @jennyf19 's comments here; AzureAD/microsoft-identity-web#470

@bgavrilMS bgavrilMS changed the title [Feature Request] Support PKCE (code_verifier) during confidential client auth code grant flows [Feature Request] [L] Support PKCE (code_verifier) during confidential client auth code grant flows Mar 18, 2021
@pmaytak
Copy link
Contributor

pmaytak commented Apr 22, 2021

This is included in MSAL 4.30.0 release.

@Ponant
Copy link

Ponant commented May 11, 2021

@pmaytak , that is great. Is there any guidance on how to implement this (auth+pkce) in Razor Pages hosted on azure with B2C, for example? I am on azure and when I declare the app as "web" I get the implicit flow, and furthermore it is not clear yet how to include pkce in the code. Some links/guidance would really help.

@jmprieur
Copy link
Contributor

@Ponant.
I suggest you just use Microsoft.Identity.Web latest version (dotnet new web --auth IndividualB2C with .NET 5.0, and then update Microsoft.Identity.Web to latest version)
This is the PR that introduced PKCE: AzureAD/microsoft-identity-web#1152

@Ponant
Copy link

Ponant commented May 11, 2021

@jmprieur , this is what I did already, the questions are:
-how to configure it in the startup/appsettings
-how to configure it in azure, I mean the app registration gives me web with implicit flow or spa with pkce. I guess I would set spa with pkce eventhough it is not a spa?
Thank you

@bgavrilMS
Copy link
Member

@Ponant - I believe there is nothing left on your part if you are using Microsoft.Identity.Web. There is no Azure app registration change needed, PKCE is an optional OAuth2 feature that is always available.

ASP.NET 5 will have this flag set to true by default.
image

Prior to the changes referenced, Microsoft.Identity.Web would force that flag to false. Today, it accepts the default, which for ASP.NET 5 I believe is true.

You should be able to double check that PKCE is used by capturing some traffic with Fiddler. You should see the initial part of PKCE when the website request the authorization code. There will be a param called code_challenge which is PKCE specific (as well as code_challenge_method).

An authorization code obtained with PKCE cannot be exchanged for an auth token without the code_verifier, which M.I.W. will manage for you. This is the protection that PKCE provides - it prevents man in the middle attacks.

@Ponant
Copy link

Ponant commented May 11, 2021

@bgavrilMS , thank you for the response. All I can say so far is that after update on .net razor page with b2c is that I need

   options.ResponseType = OpenIdConnectResponseType.Code;
    options.Scope.Add(options.ClientId);

In this way I can see the code_challenge in the uri. So to me the current template does not provide the full config with pkce, hence my questions...

As for how to register the app in azure, it seems I have to register an app as spa, which is wierd naming for a razor page.
I took this from @tedvanderveen here AzureAD/microsoft-identity-web#470
I wonder if you do not have a running template that I can look at?

@jmprieur
Copy link
Contributor

jmprieur commented May 11, 2021

@Ponant : you should not register a SPA
the redirect URI should be a web redirect URI.

Just do:

dotnet net mvc --auth SingleOrg (or --auth IndividualB2C)

then update the Nuget packages to use the latest version of Ms.Id.Web

@Ponant
Copy link

Ponant commented Jun 25, 2021

Good evening,
Look @jmprieur and @bgavrilMS, I started from scratch considering that I and @tedvanderveen are wrong. So I made
dotnet new webapp --auth IndividualB2C (.Net 6 latest preview as of today and also tried .Net 5), as you suggested.

Entered in appsettings

  "Instance": "https://xxx.b2clogin.com/tfp/",
   "ClientId": "xxx",
   "CallbackPath": "/signin-oidc",
   "Domain": "xxx.onmicrosoft.com",
   "SignedOutCallbackPath": "/signout/B2C_1_susi",
   "SignUpSignInPolicyId": "b2c_1_susi",
   "ResetPasswordPolicyId": "b2c_1_reset",
   "EditProfilePolicyId": "b2c_1_edit_profile"

Register an app in the portal as Web with a redirect url "https://localhost:5001/signin-oidc" and checked the AccessToken (not IdToken), otherwise it throws that implicit flow is not configured. The portal explicitly tells me I am using the implicit flow. In fact the app runs and the authorize url does not show a code challenge. Instead it requires a response type of the kind idtoken. So, no PKCE.

To make PKCE somewhat work is to use as a platorm as a SPA in the portal and follow the instructions @tedvanderveen has given here AzureAD/microsoft-identity-web#470 .

You keep saying that we should not register as a spa and I lexically agree on that, but to make PKCE work, I have to.
Please advise

@jmprieur
Copy link
Contributor

@Ponant:

  • did you update to the latest version of Microsoft.Identity.Web ?
  • I disagree that the redirect URI should be registered as a SPA. It should be registered as "web".

@tedvanderveen
Copy link

tedvanderveen commented Jun 25, 2021

@jmprieur @Ponant please be advised that in order to keep PKCE mode work, you now also have to set UsePkce to true in the config.
Somehow a change was introduced in more recent versions that requires this setting, that was previously not required. Found out about this undocumented breaking change, after bumping the version in my project last week.

@Ponant
Copy link

Ponant commented Jun 26, 2021

  • @jmprieur , yes I am on the latest version (1.14.0)
  • Yes it should be web as this is a confidential RP website, but it must be set as spa in the portal to get the code_challenge

Did you or can you try it out????

I even wonder if it is not because I am based in Europe, thus somehow seeing another version of the portal
Please advise

@tedvanderveen on version 1.14.0 pkce defaults to true in MicrosoftIdentityOptions

@tedvanderveen
Copy link

tedvanderveen commented Jun 26, 2021

@tedvanderveen on version 1.14.0 pkce defaults to true in MicrosoftIdentityOptions

That SHOULD be the case, PKCE FTW!

But it seems like this library now defaults to NOT to use PKCE mode lately, as I had to explicitly set UsePkce flag to true to make PKCE mode working again. Not sure what/why/how.. But it works!

@tedvanderveen
Copy link

IETF view on PKCE with confidential apps.

@tedvanderveen
Copy link

I guess in B2C the choice options Web and SPA could be merged into one. And users can opt-out from PKCE (and thereby opt-in to use a confidential client_secret during token exchange).

@jmprieur
Copy link
Contributor

jmprieur commented Jun 26, 2021

@tedvanderveen @Ponant

First, if you create your app with dotnet new webapp --auth IndividualB2C, you will only create an app that signs-in user, it won't call an API, and therefore, there is no reason to use PKCE (which is only used when you get an access token to call an API)

If you want to enable PKCE, you need to create you app with dotnet new mvc --auth IndividualB2C --called-api-url "https://localhost:12345" --called-api-scopes "api://{someguid}/access_as_user". And then, since you'll call a web API, you'll have a provide a client secret or a client certificate.

BTW, the projects you create this way use Microsoft.Identity.Web, and indeed, UsePKCE is set to true by default in the OpenIdConnectOptions or MicrosoftIdentityOptions. And Microsoft.Identity.Web only delegates to MSAL when calling a downstream web API (as MSAL is about acquiring a token).

@jennyf19
Copy link
Collaborator

@tedvanderveen in this case, web app/web API, you have to always include the secret, which is what is used to validate the client on the server side, the use of PKCE in this case is just an additional security layer, but due to the nature of the confidential client, they are secure by default against the type of attack PCKE is used for.

@tedvanderveen
Copy link

@jennyf19 no. Just no. PKCE is there to REPLACE the client secret requirement. Please read the spec..

@jennyf19
Copy link
Collaborator

@tedvanderveen you're talking for a SPA scenario then? to not have to provide a client_secret, which means it's a public client application. I was talking about web apps scenarios. For SPAs, use MSAL.JS.

@tedvanderveen
Copy link

@jennyf19 can you please take a moment to read up in the official spec I shared earlier today before posting a reply??
Let me sum it up for you here: the current best practice is to use PKCE on confidential (web)apps too. As a replacement for any client secret stuff.
Thanks.

@tedvanderveen
Copy link

And FYI: we are already using PKCE in full production workload on a .Net backend environment. With zero limitations. And no client secret blabla whatsoever.

@Ponant
Copy link

Ponant commented Jun 29, 2021

@jmprieur,
What I do not get is that virtually anyone is heading towards deprecating the implicit flow. When using only a web app I do have to set the implicit flow in the portal, just to get the idtoken. Otherwise it throws "AADB2C90057: The provided application is not configured to allow the 'OAuth' Implicit flow."
Also,
https://docs.microsoft.com/en-us/samples/azure-samples/active-directory-b2c-dotnet-webapp-and-webapi/azure-ad-b2c-call-an-aspnet-web-api-from-an-aspnet-web-app/
sets an implicit grant. I mean, the portal and docs are just stuck on implicit flows, so it is not clear what needs to be done ot have pkce working (even in your case mvc web app + api call.

@tedvanderveen, the spa option does not seem to work anymore after update to the latest nuget (1.14.0). I am getting the errors you had (again).
That is pretty frustrating.

@tedvanderveen
Copy link

@Ponant I had same when upgrading to recent version. I could fix it by explicitly setting config options UsePkce to true. Did you give that a try?

@Ponant
Copy link

Ponant commented Jun 29, 2021

@tedvanderveen , yes I did because you mentionned it a few days ago, but it did not work out. In short, SPA with idtoken and access token checked out in the portal does not work anymore. Even with options.UsePkce=true from the MicrosoftIdentityOptions.

@tedvanderveen
Copy link

@Ponant sad story. Assuming nothing changed on the side of B2C, this means it's client tooling was broken since version 1.14.0? Good to know, will hold off on bumping until workaround is found.

@jmprieur
Copy link
Contributor

jmprieur commented Jun 29, 2021

@Ponant

What I do not get is that virtually anyone is heading towards deprecating the implicit flow. When using only a web app I do have to set the implicit flow in the portal, just to get the idtoken. Otherwise it throws "AADB2C90057: The provided application is not configured to allow the 'OAuth' Implicit flow."

Yes, this is an issue the B2C service is aware of, and they are working on it.

https://docs.microsoft.com/en-us/samples/azure-samples/active-directory-b2c-dotnet-webapp-and-webapi/azure-ad-b2c-call-an-aspnet-web-api-from-an-aspnet-web-app/
sets an implicit grant. I mean, the portal and docs are just stuck on implicit flows, so it is not clear what needs to be done ot have pkce working (even in your case mvc web app + api call.
Thanks for the heads-up on this one. This should no longer be necessary when using AAD (it's still with B2C)

But this is not implicit flow. It's hybrid flow

@Ponant
Copy link

Ponant commented Jun 29, 2021

Yes you are right but I feel all of this is very confusing. I saw a few posts on stackoverflow. In the end even of pkce is a spec it remains a naturally more viable solution than the implicit or hybrid flow. So I still do not understand why we can’t have this with a confidential app with proper documentation or code + portal configuration. In any case thank you for having taken the time to answer

@tedvanderveen
Copy link

@Ponant @jmprieur PKCE on B2C works. This .Net client handles it fine. We have it running in production .Net backend app. Without client secrets.
It's just that you have to pick the "single page application" branded option in B2C to set things up.

@tedvanderveen
Copy link

Dit some further investigation using Fiddler to compare B2C communication between version 1.10.0 and 1.11.0
See AzureAD/microsoft-identity-web#1294

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests