okta-oidc-js
okta-oidc-js copied to clipboard
Confused? Is Okta auth in Android apps shareable with webviews?
I'm submitting this issue for the package(s):
- [ ] jwt-verifier
- [ ] okta-angular
- [x] oidc-middleware
- [ ] okta-react
- [x] okta-react-native
I'm submitting a:
- [ ] Bug report
- [ ] Feature request
- [x] Other (Describe below)
Current behavior
I'm new to Okta and trying to navigate the best way to incorporate Okta authentication in native apps (iOS/Android) to SSO with webviews opened by these apps to apps protected by the same Okta domain. I've been able to get this working in iOS using the custom-sign-in example in https://github.com/okta/samples-js-react-native and the information to setup usePersistentCookie. On Android, however, I'm not connecting the dots. Is this possible? I've seen an issue reference Chrome Custom Tabs and how cookies can't be shared to a webview from there, but it doesn't look like the custom-sign-in example uses that on Android. The browser-sign-in example is documented as returning a code to the app which is then exchanged for an access token and id token, so it doesn't appear that there's any cookie being set that a webview could inherit in this approach, either?
Expected behavior
Both Android and iOS platforms have an Okta SSO mechanism to embedded webviews from the native application.
Minimal reproduction of the problem with instructions
Run https://github.com/okta/samples-js-react-native apps on Android and use a webview (e.g. https://github.com/react-native-community/react-native-webview) to load an Okta web app protected in the same domain - should work w/o prompting for login again.
Extra information about the use case/user story you are trying to implement
Implement a hybrid native app with some native functionality and some webview functionality under the same Okta domain without requiring multiple logins on Android.
Environment
- Package Version: okta-react-native 1.4.0
- Browser: n/a
- OS: Android Q (29)
- Node version (
node -v): 12.6.3 - Other:
@bdruth - Thanks for the question, I'll forward this to team members that can speak intelligently about react-native and see if we can get you an answer.
@bdruth Webview is not the recommended way to implement OIDC flow in the native app. Quoted from https://www.linkedin.com/pulse/webviews-bad-use-appauth-mike-schwartz/
In a WebView any malicious code in the page has the same rights as your application, so you should make sure you only load trusted content. But there is another risk–a malicious app may also have access to browser content (like cookies) and may snoop passwords or intercept OAuth codes.
For the browser-sign-in, you may need to listen on signInSuccess event to get the tokens after redirect, like https://github.com/okta/samples-js-react-native/blob/82b302de87a1d8d0213bff4899604202aef1d312/browser-sign-in/App.js#L51-L54
If you want to implement customized UI, you can follow the custom-sign-in sample to build your native UI, then call signIn function from @okta/okta-react-native to acquire token.
signIn({ username, password })
.then(token => {
// do things with acquired token
});
OK - that jives with some of the things I've read. What I'm not clear on is what to do with the acquired token so that there's a seamless SSO? I'm not married to using webviews, and I've read that Chrome Custom Tabs on Android might be the better option, though it's bizarre that those are two completely different things in react-native, and the cross-platform behavior is completely different for Chrome Custom Tabs ... ideally there'd be a simple way to use webviews on iOS and Chrome Custom Tabs on Android in an effectively identical way from React Native, but I digress ...
@bdruth The @okta/react-native has implemented the browser sign-in flow based on the android custom tab, you can use it by calling signIn function without providing any arguments.
Right ... but I need custom sign-in. So, how do I use custom sign-in and pass what to a Chrome Custom Tab?
For custom signin in react native you will need to build your own sign in UI, instead of using custom tabs to open the okta login page.
https://github.com/okta/okta-react-native#custom-sign-in
Right - I'm following all that. I have the custom-sign-in working from the Okta react-native samples. All good with custom-sign-in, but ... how do I SSO that to something, anything that can load a web page ... I don't really care if it's Chrome Custom Tabs or webviews at this point.
@bdruth If I understand your question correctly. You want to implement the SSO as the app redirects the user to a webpage (OKTA domain) to start the sign in process, then it redirects user back to the app after success sign in. If that's the case, it is the browser sign in flow that provides from the sdk. It is implemented by using custom tabs in android.
Or you want to customize any step in the browser sign in flow?
No, that's not correct. We're looking at how we would have a native app, with native (custom sign-in flow), that will have native functionality in hybrid with loading web pages from existing / legacy secured systems. Both are setup in Okta using OIDC (there may be future need for SAML, too, but right now our test bed is using OIDC). Current behavior is:
- user launches app for the first time, signs in using custom sign-in flow, accesses a view that loads a secured web-page and is redirected to the Okta sign-in screen.
desired behavior is:
- user launches app for the first time, signs in using custom sign-in flow, accesses a view that loads a secured web-page and when redirecting for authentication, Okta recognizes the user is signed in and redirects back to the secured web-page with the necessary auth headers/cookies/whatever set
This is working in iOS using the usePersistentCookie and sharedCookiesEnabled on the react-native-webview. So, the question is, how do we accomplish this in the Android ecosystem.
Hi @bdruth,
The android native sdk needs to have webview support. I have an experimental branch with this webview but this is not something we are planning to support. If you like I can share the patch with you.
@FeiChen-okta - feel free to share patch. So, if I'm understanding correctly, the only way to have SSO between native & web content on Android is to use the browser-sign-in flow? Custom sign-in (without your experimental, unsupported patch) is not possible, irrespective of Chrome Custom Tabs or Webview?
Hi @bdruth We have a couple of different configurations
-
custom-sign-in: To make SSO work for your legacy web pages you'll have to get the response headers from the customsignIncall and set those headers inreact-native-webview -
browser-sign-in-chrome-tabs: This will not work for your legacy web pages if usingreact-native-webviewsince the sessions are stored in chrome and not webview. If you open your legacy web pages with chrome custom tabs then it will work but I'm not sure ifreact-native-webviewsupports it. -
browser-sign-in-webview: This will require the following patch. This will make oidc sdk use webview instead of chrome custom tabs. This way the session is already in webview soreact-native-webviewshould work.
You can apply the following patch to the master branch in https://github.com/okta/okta-oidc-android Once you've compiled the aar you'll have to add it to the android bridge. 0001-Webview-support.patch.txt
@FeiChen-okta thank you! So, I'm assuming I need to actually call signIn from @okta/okta-auth-js as is being done by the signIn call in okta-react-native, since the signIn exposed by okta-react-native is only returning the access token as far as I can tell? Or is there a way to make the call through okta-react-native?
@okta/okta-react-native#index.js
export const signIn = async(options) => {
// Custom sign in
if (options && typeof options === 'object') {
return authClient.signIn(options)
.then((transaction) => {
const { status, sessionToken } = transaction;
if (status !== 'SUCCESS') {
throw new Error('Transaction status other than "SUCCESS" has been return, please handle it properly by calling "authClient.tx.resume()"');
}
return authenticate({ sessionToken });
})
.then(token => {
if (!token) {
throw new Error('Failed to get accessToken');
}
return token;
})
.catch(error => {
throw new OktaAuthError('-1000', 'Sign in was not authorized', error);
});
}
Hi @bdruth Currently the react-native SDK does not support a way to get the headers from the Android bridge. So you'll need a way to get the response header from HttpClientImpl.java to react-native layer and set the cookies in react-native-webview
Or the other way around where react-native set a boolean flag similar to iOS sharedCookiesEnabled. This is then propagated to HttpClientImpl and it will use CookieManager to set the cookies for WebView
After these changes signIn should set the correct cookies in WebView depending on which path you implement.
Unfortunately both methods require some changes to the SDK. I believe the react-native to Android way is the simplest since that seems to be the way react-native-webview is enabling cookies in iOS.
K, I'll take a look and see what I can come up with. Thanks much for your assistance thus far!
@bdruth I am facing the same issue now. Have you workaround this? Tks