ActiveLogin.Authentication icon indicating copy to clipboard operation
ActiveLogin.Authentication copied to clipboard

Better support for in-app browser logins

Open sturlaj opened this issue 3 years ago • 8 comments

When performing browser based flows within an app activelogin samedevice mode does not support redirects back to the app. For instance when using WebAuthenticator in Xamarin.

https://docs.microsoft.com/en-us/xamarin/essentials/web-authenticator?tabs=android

The link that is generated (within the app browser session) will typically look something like this. While authentication works, the BankId app will return the user to the browser window instead of the the original app.

https://app.bankid.com/?autostarttoken=5da4c0d8-1cda-4ae6-a914-7ad669931cee&redirect=https%3A%2F%2Flocalhost%3A44322%2FBankIdAuthentication%2FLogin%3FreturnUrl%3D%252Fsignin-bankid-samedevice%26loginOptions%3.....

Is there a recommended way to return to the app and successfully continue the login. Maybe by wrapping the redirect url in an app url scheme and handling it in the app (maybe in IBankIdLauncher.GetLAunchInfo)?

sturlaj avatar Feb 16 '22 13:02 sturlaj

Hi @sturlaj and thank you for reporting this.

We don't have any "out of the box" support for returning right away to an app. The main reason is that the return URL will differ depending on your OS and what scheme you've registered for your app.

We have implemented this for clients multiple times, and the solution is to override the interface that is responsible for figuring out the launch info. We have some documentation on it here: https://github.com/ActiveLogin/ActiveLogin.Authentication/blob/main/docs/bankid.md#custom-browser-detection-and-launch-info

In the future we could do some improvements on this scenario, but it's not in our near term roadmap.

PeterOrneholm avatar Feb 17 '22 11:02 PeterOrneholm

@PeterOrneholm Much appreciated feedback. So you can confirm that this is the recommended approach? Basically wrapping the return url in some app specific url scheme, and have the app open the return url in its already open browser session? I assume the app would have to validate the authority url to avoid malicious attempts to open in-app browser.

sturlaj avatar Feb 17 '22 12:02 sturlaj

I can't give a generic official recommendation here, exactly how you handle the return URL depends on your scenario. But the place to override the URL handling is by using that interface.

We could look into your specific case if you want to, look at the flow, and ensure it works in a safe way, but that would be part of our commercial support. See "Active Login Support" here: Active Login Support

PeterOrneholm avatar Feb 18 '22 15:02 PeterOrneholm

I'll leave this issue open as the base request still holds, we could support some better support for this out of the box.

PeterOrneholm avatar Feb 18 '22 15:02 PeterOrneholm

When a user opens our website in Instagram (embedded view) and tries to sign in, the auth process does not complete. Instead it fails with some generic message "Could not load the page".

In the logs it seems we end up in the "invalid state handler".

Is this use-case related to this issue?

span avatar Jun 09 '22 07:06 span

Very interesting @span! Do you have any more details from the logs?

If it is an embedded webview, in for example Instagram, we won't redirect the user back to that app and the user instead manually needs to switch application. I'm not sure why such error message would appear though.

PeterOrneholm avatar Jun 10 '22 09:06 PeterOrneholm

Any more input on this? See my question here as well: https://github.com/ActiveLogin/ActiveLogin.Authentication/issues/376#issuecomment-1218030591

An idea I have is to add a simple sample to the documentation on how to override the link generation to always return "manual mode" where the user needs to close the bankid app and go back to the previous app. If your users usually comes this way, it might be something good to do.

PeterOrneholm avatar Aug 22 '22 14:08 PeterOrneholm

We have this issue with an iOS app not being redirected back to the app's web view, but instead the BankID App launches a new Safari browser window and hence the login process can not be completed. The link to the documentation from Feb 17 doesn't seem to work...

On Android it works as it doesn't use the redirect from BankID.

Could a possible solution be for the BankID app to "switch back" to the mobile app (by using a applink or whatever it's called in the redirect=) and if the webview is still open in that app the Identity Server login flow will pick up and finish and eventually redirect back to app again?

jenspettersson avatar Sep 27 '22 18:09 jenspettersson

@jenspettersson did you manage to find a solution for this? We have the same issue in our iOS app.

arevarnTH avatar Nov 14 '22 08:11 arevarnTH

@jenspettersson did you manage to find a solution for this? We have the same issue in our iOS app.

We extended our Identity Server implementation to allow a native_redirect parameter to be sent by the client in the authorize step and made sure that the BankID launcher used that one instead of the default one that forced the BankID app to open a new browser window.

From our client:

options.Events = new OpenIdConnectEvents
{
	OnRedirectToIdentityProvider = c =>
	{
		//...some code omitted but we detected that this client needed  a native_redirect uri so 
                //we set that in the context and passed that as a new parameter to the idsr redirect

		c.ProtocolMessage.Parameters.Add("native_redirect", nativeRedirect);

		return Task.CompletedTask;
	}
};

As we also managed the idsrv implementation we added support for this new "protocol message parameter".

Not sure this is the best approach, but it works for us.

jenspettersson avatar Nov 14 '22 08:11 jenspettersson

@jenspettersson did you manage to find a solution for this? We have the same issue in our iOS app.

We extended our Identity Server implementation to allow a native_redirect parameter to be sent by the client in the authorize step and made sure that the BankID launcher used that one instead of the default one that forced the BankID app to open a new browser window.

From our client:

options.Events = new OpenIdConnectEvents
{
	OnRedirectToIdentityProvider = c =>
	{
		//...some code omitted but we detected that this client needed  a native_redirect uri so 
                //we set that in the context and passed that as a new parameter to the idsr redirect

		c.ProtocolMessage.Parameters.Add("native_redirect", nativeRedirect);

		return Task.CompletedTask;
	}
};

As we also managed the idsrv implementation we added support for this new "protocol message parameter".

Not sure this is the best approach, but it works for us.

Thanks for your answer! Did you also need to use app link or url scheme in your native redirect?

arevarnTH avatar Nov 14 '22 12:11 arevarnTH

Revisiting this now (as we've had a few different cases on exact this recently). I'll try to write more detailed in the documentation, but it boils down to:

When you are signing into BankID from an app, specifically iOS (as Android redirects back to the last app, not by URL) the website hosting Active Login will be embedded into the app using a Web View. The webview will have a user agent that says it is Safari (as Safari is what Web View uses). Therefore, the built in code will think the flow was launched from Safari and therefore redirect back to a normal https:// which iOS will launch in Safari.

You can handle this by implementing your own version of IBankIdLauncher, I would suggest basing that on BankIdLauncher.

First - you need to detect if the site is launched from within your app. Either by modifying the User Agent of the WebView or by figuring that out by some custom URL. If you think it is your special app (could also be built in browser in Facebook/Instagram etc). then you should modify these:

GetLaunchUrl: This needs to return your app prefix (that you need to register). For example: my-app://auth

GetDeviceWillReloadPageOnReturnFromBankIdApp: By default Safari on iOS will reload the tab when you return, that is not the default scenario going back to a custom app with a webview. Therefore you will have to return false in this method.

Right now, BankIdLauncher is internal so you can't inherit from it. I would like it to stay so. But that means you will have to copy-paste it to make modifications. I have one idea for an interface that would make the custom app scenario so much easier.

The interface could look something like this:

public interface IBankIdLauncherCustomAppCallback
{
   public Task<bool> IsCustomApp();
   public Task<string> GetCustomAppReturnUrlScheme();
}

My idea is that BankIdLauncher would take a list of the IBankIdLauncherCustomAppCallback implementations. Ask them one by one if they are relevant (IsCustomApp) and use the scheme for the first relevant app it finds. If none is found, then it falls back to the default implementation. This would allow for a pluggable model where we can register small implementations for specific browsers, like: .AddBrowserSupportInstagram().

Any feedback on that?

PeterOrneholm avatar Dec 02 '22 13:12 PeterOrneholm

There is now a PR, please have a look :)

https://github.com/ActiveLogin/ActiveLogin.Authentication/pull/414

PeterOrneholm avatar Jun 07 '23 20:06 PeterOrneholm

I note that the new interface IBankIdLauncherCustomAppCallback does not allow me to control GetDeviceWillReloadPageOnReturnFromBankIdApp so that I can return false. Are there any plans to allow that?

altenstedt avatar Sep 03 '23 07:09 altenstedt

I note that the new interface IBankIdLauncherCustomAppCallback does not allow me to control GetDeviceWillReloadPageOnReturnFromBankIdApp so that I can return false. Are there any plans to allow that?

Good question! You can still implement BankIdLauncher to achieve that, the IBankIdLauncherCustomAppCallback was supposed to be a shorthand for that very specific scenario, but tell me more about the usecase and maybe it would be relevasnt to add something similar for GetDeviceWillReloadPageOnReturnFromBankIdApp as well :)

PeterOrneholm avatar Sep 03 '23 18:09 PeterOrneholm

My use-case is as you described in the comment above. The custom native iOS app render the IdP in an embedded web view, so we need to disable the browser refresh on iOS.

The implementation of IBankIdLauncher that we have today works great. If I could only override the behaviour in GetDeviceWillReloadPageOnReturnFromBankIdApp I could replace our implementation with something simpler :-)

altenstedt avatar Sep 05 '23 18:09 altenstedt

Sounds very legit :) Could you crate a new issue for that and we'll see how and when we can add it (a PR is always welcome... :) )?

PeterOrneholm avatar Sep 05 '23 19:09 PeterOrneholm