capacitor-community / generic-oauth2

Generic Capacitor OAuth 2 client plugin. Stop the war in Ukraine!
MIT License
223 stars 106 forks source link

Issues with "msauth://" Azure AD B2C redirect URI #169

Closed sdgluck closed 2 years ago

sdgluck commented 2 years ago

Description

Some things to note:

The redirect URI that is produced by Azure B2C does not match up with what is in the documentation.

This is the form that I see in Azure portal which allows to create an Android redirect URI:

image

Once filled in, the URI I am given is in this form:

msauth://<PACKAGE_NAME>/<SIGNATURE_HASH>

Example:

msauth://com.sdgluck.app/y9LmDcNdfd2GEnSGdV9tY2lUBE7%3D

As you can see, this differs to what is in the documentation, which states the redirect scheme should be the package name, eg. com.sdgluck.app.

The following happens when I invoke login through the plugin:

If I inspect this blank page using Chrome DevTools, I can see the following message is printed to the console:

Navigation is unreachable: msauth://com.sdgluck.app/y9LmDcNdfd2GEnSGdV9tY2lUBE7%3D?state=<state>&code=<code>

(I have substituted the query param values with placeholders.)

This indicates to me that the msauth scheme is not being handled by the app. This makes sense, because I did not declare any intent in the manifest file which uses the msauth scheme.

I have tried a number of ways of adding an intent which uses the msauth scheme. It works in so much as the in-app browser closes and the app handles the redirect URL with the msauth scheme, however I then see such errors as these in the app debug logs:

2021-08-04 15:24:12.920 21357-21357/com.sdgluck.app.debug E/Capacitor/Plugin: ERR_GENERAL
    java.lang.IllegalArgumentException: exactly one of authResponse or authException should be non-null
        at net.openid.appauth.Preconditions.checkArgument(Preconditions.java:116)
        at net.openid.appauth.AuthState.update(AuthState.java:375)
        at com.byteowls.capacitor.oauth2.OAuth2ClientPlugin.handleAuthorizationRequestActivity(OAuth2ClientPlugin.java:334)
        at com.byteowls.capacitor.oauth2.OAuth2ClientPlugin.handleOnNewIntent(OAuth2ClientPlugin.java:308)
2021-08-04 15:24:12.922 21357-21357/com.sdgluck.app.debug D/Capacitor: Sending plugin error: {"save":false,"callbackId":"36104728","pluginId":"OAuth2Client","methodName":"authenticate","success":false,"error":{"message":"ERR_GENERAL"}}

2021-08-04 15:24:13.118 21357-21357/com.sdgluck.app.debug I/Capacitor/Console: File: webpack-internal:///./lib/auth/implementations/app_azure_ad.ts - Line 71 - Msg: Error: ERR_ANDROID_NO_INTENT
2021-08-04 15:24:13.123 21357-21357/com.sdgluck.app.debug E/Capacitor/Console: File: webpack-internal:///./lib/auth/implementations/app_azure_ad.ts - Line 72 - Msg: OAuth rejected Error: ERR_ANDROID_NO_INTENT

Another thing to note is that we use a custom scheme for deep linking in our app, so the custom_url_scheme string is something like sdgluck instead of com.sdgluck.app. I'm not sure how that fits in with the way schemes are meant to be configured for compatibility with this plugin and Azure AD B2C's msauth scheme.

Thanks for any help you are able to offer.

Capacitor version:

$ npx cap doctor
💊   Capacitor Doctor  💊

Latest Dependencies:

  @capacitor/cli: 3.1.2
  @capacitor/core: 3.1.2
  @capacitor/android: 3.1.2
  @capacitor/electron: 3.1.2
  @capacitor/ios: 3.1.2

Installed Dependencies:

  @capacitor/cli 2.4.0
  @capacitor/android 2.4.0
  @capacitor/ios 2.4.2
  @capacitor/core 2.4.0
  @capacitor/electron not installed

Library version:

2.1.0

OAuth Provider:

Azure AD B2C

Your Plugin Configuration

{
  appId: process.env.NEXT_PUBLIC_AZURE_AD_APP_ID,
  authorizationBaseUrl: process.env.NEXT_PUBLIC_AZURE_AD_AUTH_BASE_URL,
  accessTokenEndpoint: "",
  scope: "openid offline_access",
  responseType: "token",
  android: {
    pkceEnabled: true,
    responseType: "code",
    redirectUrl: process.env.NEXT_PUBLIC_AZURE_AD_ANDROID_REDIRECT_URL,
    accessTokenEndpoint: process.env.NEXT_PUBLIC_AZURE_AD_ACCESS_TOKEN_ENDPOINT,
    handleResultOnNewIntent: true,
    handleResultOnActivityResult: true,
  },
  ios: {
    pkceEnabled: true,
    responseType: "code",
    redirectUrl: process.env.NEXT_PUBLIC_AZURE_AD_IOS_REDIRECT_URL,
    accessTokenEndpoint: process.env.NEXT_PUBLIC_AZURE_AD_ACCESS_TOKEN_ENDPOINT,
  },
}

Let me know if you need to see any of the actual values which are represented as env vars in the config.

moberwasserlechner commented 2 years ago

Please update to the latest plugin version. It works there but it requires capacitor 3.x.

sdgluck commented 2 years ago

Please update to the latest plugin version. It works there but it requires capacitor 3.x.

Thank you for the quick reply. We will start looking at upgrading Capacitor then.

Can you provide a little more detail as to why upgrading to Capacitor v3, and the latest plugin version, fixes the issue?

moberwasserlechner commented 2 years ago

I did not use Azure B2C before in a real project but for the 3.0.0 release I did all my testing with Azure B2C and Google Login.

As I released the plugin 2 days ago I know that it works with Azure B2C because I registered a fresh App in the Azure Portal for all platforms.

Unfortunately I do not know why you have an issue in the old version.

You can try to adapt the new docs https://github.com/moberwasserlechner/capacitor-oauth2#android-1 but I can not help you with it as I'm not using Azure B2C in versions earlier than 3.0.0

moberwasserlechner commented 2 years ago

Let's keep this task open for a couple of days. Maybe someone can help you.

I will close it in approx. 7 days if it is still open.

sdgluck commented 2 years ago

Using the docs that you linked to, we were able to get it working with plugin version 2.1.0 and Capacitor v2. Thanks for linking us to the correct part of the documentation.

One thing the docs didn't cover which was required for us before it worked, is changing the appAuthRedirectScheme to msauth in the build.gradle file, like this:

defaultConfig {
        // ...
        manifestPlaceholders = [
            "appAuthRedirectScheme": "msauth"
        ]
    }

We only use Azure AD B2C though, and I'm not sure whether this change would be compatible with other providers should anyone be reading this who uses multiple IdPs.

I will close the issue now we have everything working.

Thanks again for your assistance, and time and effort maintaining the plugin.

sdgluck commented 2 years ago

Quick follow up... We found that including our own intent filter for msauth:// in our manifest was unnecessary. It seems the underlying OAuth library used by this plugin configures an intent filter for us (using appAuthRedirectScheme above), so with the additional one in the manifest, when the user was redirected back to the app after successful authn, the app drawer would appear with two items: one for the application (set by the underlying library, AFAICT), and one for the activity (set by us). The latter item in the app drawer would cause the app to fail to obtain the token from Azure. We removed our own intent filter from the manifest, and everything behaves as it should: no app drawer displays on redirect back to the app, and the plugin obtains the necessary tokens from the provider.

meriturva commented 1 year ago

@moberwasserlechner using capacitor 4 with Azure MSAL2 i had to set "appAuthRedirectScheme": "msauth" otherwise intent doesn't work. I think it is helpful to all to include it on the current readme!

vdominguezcxp commented 6 months ago

For anyone in a similar situation, this is still the solution to get it working on android using capacitor 5. Please update the readme