okta-react-native icon indicating copy to clipboard operation
okta-react-native copied to clipboard

Okta SSO from Mobile app to Web view

Open jcra opened this issue 5 years ago • 23 comments

I'm submitting a:

  • [ ] Bug report

Current behavior

Briefly here is the scenario we have:

  1. The mobile app uses the Okta Native SDK to authenticate the user (https://github.com/okta/okta-react-native)
  2. When accessing the page from the Web app, it opens the page in a WebView. The question is how the web app should authenticate the users when the page is loaded from the mobile app without asking for a password again.

Expected behavior

Keep the session between the mobile app and the web

Minimal reproduction of the problem with instructions

Extra information about the use case/user story you are trying to implement

Environment

  • Package Version:
  • React Native Version: 1.10.0
  • OS:
  • Node version (node -v):
  • Other:

jcra avatar Apr 21 '21 18:04 jcra

Hi @jcra thanks for choosing okta!

Unfortunately, we don't support this functionality right now, and we've got feature requests for this in the past (https://github.com/okta/okta-oidc-android/issues/188)

Our react-native SDK is a wrapper around our native iOS/Android SDKs.

Feel free to follow the linked issue for updates on our progress!

JayNewstrom avatar Apr 21 '21 19:04 JayNewstrom

@JayNewstrom thanks for the response, do you know if this feature is in the roadmap for future releases ?

jcra avatar Apr 23 '21 19:04 jcra

It's on our backlog of things to look into, it's not yet clear if or what kind of solution we'll provide. This is something that doesn't strictly have to be implemented in the SDK, we expose everything for it to happen in application code. So it may end up just being a sample.

In the case of the react native SDK, it would certainly be nice to provide a unified approach between iOS and Android, so there is some motivation to do it here.

JayNewstrom avatar Apr 23 '21 19:04 JayNewstrom

@JayNewstrom do you have a sample code on how this could be implemented from the app code.

jcra avatar Apr 23 '21 19:04 jcra

The closest we have right now is just some ideas on approaches in the linked issue.

JayNewstrom avatar Apr 23 '21 20:04 JayNewstrom

@jcra If I understood you correctly you have 2 apps. You do an authentication in first app you want a second app to not prompt user for entering credentials when launching a webview. If thats the case you should take into consideration two things with current workaround ideas:

  1. You would need to handle data transferring yourself(e.g. via content provider on android)
  2. It would be harder to share session from the second app, and could present some inconveniences when users have a valid session in a second app but not in first For this case you can do the following, use your webview to authenticate and then debug its cookie storage, youll need to see what your app needs in order to do an auth, youll want to look into this entry https://github.com/okta/okta-oidc-android/issues/188#issuecomment-775033253. Then you would want to replicate this entry by doing an auth from the first app, you could also refer to a linked thread https://github.com/okta/okta-oidc-android/issues/188 to see how theyve achieved this and set this cookie manually while running your web view. You probably would face new questions while doing this, so please feel free to reach out

NikitaAvraimov-okta avatar Apr 28 '21 15:04 NikitaAvraimov-okta

It's on our backlog of things to look into, it's not yet clear if or what kind of solution we'll provide. This is something that doesn't strictly have to be implemented in the SDK, we expose everything for it to happen in application code. So it may end up just being a sample.

@JayNewstrom - I have this scenario mostly working in application code. The issue I'm facing is that after obtaining the session cookie and tokens, there does not appear to be an exposed SDK method to store the tokens, nor does the OktaAuth client in this environment have token or tokenManager available. If token storage isn't exposed from the SDK, is there a way to plugin a custom storage provider on the react-native side?

wcarson avatar May 03 '21 20:05 wcarson

Hi @wcarson glad to hear you've made progress!

We don't expose a lot of the more powerful features of our native SDKs to react native, however, you could get to them yourself by copying the code out of this repo into your own, and making modifications there. On Android, we have an interface you can set https://github.com/okta/okta-oidc-android#storage for example.

Another option would be for us to add some new functionality to the react native SDK. What types of methods are you looking for? Just a storeTokens(id_token, access_token, refresh_token)?

JayNewstrom avatar May 04 '21 14:05 JayNewstrom

Hi @JayNewstrom, I think storeTokens and verifyTokens are the only new methods needed for this use case as all of the other token related methods (getAccessToken, isAuthenticated, etc.) are already exposed. The only other thing that would make this easier would be to get access to the response object containing tokens and session cookie. Currently I have to get the tokens & cookie manually (fetch). The process currently looks like this:

  1. Obtain session token using okta-auth-js signin.
  2. Exchange session token for id/access/refresh tokens (currently manual using fetch)
  3. Grab tokens and session cookie from response
  4. Validate tokens and store (using react-native-pure-jwt and react-native-encrypted-storage libraries)
  5. Save cookie in cookie manager (using @react-native-cookies/cookies )

Now when Okta is accessed in a web view, the session cookie is sent along and voila...SSO.

As mentioned above, the 2 things that are currently a pain are token validation/storage and obtaining the session cookie.

-Wayne

wcarson avatar May 04 '21 15:05 wcarson

This is a great write up @wcarson thanks so much!

JayNewstrom avatar May 04 '21 15:05 JayNewstrom

Hi @wcarson, would you mind sharing how you are handling step 2 in your process? Are you using the /authorize endpoint? I'm having a weird issue where I can see the session cookie through Postman but not in the response body in the app.

bjjeong avatar May 25 '21 20:05 bjjeong

Hi @wcarson, would you mind sharing how you are handling step 2 in your process? Are you using the /authorize endpoint? I'm having a weird issue where I can see the session cookie through Postman but not in the response body in the app.

@bjjeong - Yes, using the /authorize endpoint, then grabbing the Set-Cookie header on the response and saving it in the cookie manager (step 5 in my flow above)

wcarson avatar May 26 '21 15:05 wcarson

Hi @wcarson, would you mind sharing how you are handling step 2 in your process? Are you using the /authorize endpoint? I'm having a weird issue where I can see the session cookie through Postman but not in the response body in the app.

@bjjeong - Yes, using the /authorize endpoint, then grabbing the Set-Cookie header on the response and saving it in the cookie manager (step 5 in my flow above)

Thank you! An interesting discovery while trying this - when I use fetch rather than axios, the session cookie (sid) is automatically stored and retrievable using react-native-cookies. For some reason the cookie wasn't being set with axios.

bjjeong avatar May 27 '21 00:05 bjjeong

@bjjeong - fwiw I used axios and had to manually get the Set-Cookie header and give it to react-native-cookies (CookieManager.setFromResponse())

wcarson avatar May 27 '21 01:05 wcarson

Hi @JayNewstrom, I think storeTokens and verifyTokens are the only new methods needed for this use case as all of the other token related methods (getAccessToken, isAuthenticated, etc.) are already exposed. The only other thing that would make this easier would be to get access to the response object containing tokens and session cookie. Currently I have to get the tokens & cookie manually (fetch). The process currently looks like this:

  1. Obtain session token using okta-auth-js signin.
  2. Exchange session token for id/access/refresh tokens (currently manual using fetch)
  3. Grab tokens and session cookie from response
  4. Validate tokens and store (using react-native-pure-jwt and react-native-encrypted-storage libraries)
  5. Save cookie in cookie manager (using @react-native-cookies/cookies )

Now when Okta is accessed in a web view, the session cookie is sent along and voila...SSO.

As mentioned above, the 2 things that are currently a pain are token validation/storage and obtaining the session cookie.

-Wayne

It would be nice if okta-react-native could expose the session token too instead of only the access token, so we could run step 1 without having to use okta-auth-js directly

gabrielmirandat avatar Jun 01 '21 21:06 gabrielmirandat

We ended up scrapping the approach I outlined above. The primary reason was that once the session cookie expired (e.g. the user doesn't use the mobile app for a few days), there was no way to get it back without having the user login again. This wasn't acceptable in our case. What we ended up doing was building a simple OAuth2 to SAML translator in our service layer where you can present a valid access token and get a "magic link" which SSOs into Okta via SAML. This works well and addresses the cookie expiration issue I described above.

-Wayne

wcarson avatar Jun 01 '21 21:06 wcarson

We ended up scrapping the approach I outlined above. The primary reason was that once the session cookie expired (e.g. the user doesn't use the mobile app for a few days), there was no way to get it back without having the user login again. This wasn't acceptable in our case. What we ended up doing was building a simple OAuth2 to SAML translator in our service layer where you can present a valid access token and get a "magic link" which SSOs into Okta via SAML. This works well and addresses the cookie expiration issue I described above. -Wayne

That is great! So you ended implementing this translation. Can you share any docs or samples in how to do this? And how to integrate this link with Okta? I believe it would bring a lot of value in this conversation. Tks

gabrielmirandat avatar Jun 02 '21 12:06 gabrielmirandat

@gabrielmirandat - We're in the process of adding this in to our service layer, but have a working proof of concept. It's pretty simple actually. The process goes something like this:

  1. App: Call API with access token to request SSO link specifying target URL as a parameter.
  2. API: Validate access token
  3. API: Construct SAML Response (we used ITfoxtec .NET SAML Library)
  4. API: Store SAML Response in distributed cache (e.g. Redis)
  5. API: Construct and return SSO link to app. The SSO link contains the cache key for the SAML Response so it can be retrieved later (step 7)
  6. App: Launch SSO link from step 5 from WebView
  7. API: Retrieve SAML Response from cache and remove from cache (i.e. the SSO link is single-use)
  8. API: Perform IdP initiated SSO with Okta (i.e. post SAML Response)
  9. Okta: Perform inbound SAML SSO and return browser to originally specified target URL (relay state) with Okta session

Note: Cache and SAML Response should have very short expirations.

Here's a gist of the original proof of concept code.

HTH

-Wayne

wcarson avatar Jun 03 '21 14:06 wcarson

Hi @JayNewstrom, I think storeTokens and verifyTokens are the only new methods needed for this use case as all of the other token related methods (getAccessToken, isAuthenticated, etc.) are already exposed. The only other thing that would make this easier would be to get access to the response object containing tokens and session cookie. Currently I have to get the tokens & cookie manually (fetch). The process currently looks like this:

  1. Obtain session token using okta-auth-js signin.
  2. Exchange session token for id/access/refresh tokens (currently manual using fetch)
  3. Grab tokens and session cookie from response
  4. Validate tokens and store (using react-native-pure-jwt and react-native-encrypted-storage libraries)
  5. Save cookie in cookie manager (using @react-native-cookies/cookies )

Now when Okta is accessed in a web view, the session cookie is sent along and voila...SSO.

As mentioned above, the 2 things that are currently a pain are token validation/storage and obtaining the session cookie.

-Wayne

Thank you, @wcarson . Me and my team are studying the possibility to change our app's auth method from OIDC to SAML.

In the meantime, I'm struggiling to run the first step in your older post. Have you used only okta-auth-js to log in or used okta-react too (like here https://developer.okta.com/code/react/okta_react/#create-a-react-app). How did you do this log in, could you post a sample in how to configure and make the call? Were you still using okta-react-native to do the routing stuff?

Best regards

gabrielmirandat avatar Jun 04 '21 20:06 gabrielmirandat

@gabrielmirandat - this was all it was in my proof of concept:

import { OktaAuth } from '@okta/okta-auth-js';
...
const authClient = new OktaAuth({ 
  issuer: config.issuer 
});
...
const signInResult = await authClient.signIn(options);
const { status, sessionToken } = signInResult || {};

wcarson avatar Jun 05 '21 04:06 wcarson

@gabrielmirandat - this was all it was in my proof of concept:

import { OktaAuth } from '@okta/okta-auth-js';
...
const authClient = new OktaAuth({ 
  issuer: config.issuer 
});
...
const signInResult = await authClient.signIn(options);
const { status, sessionToken } = signInResult || {};

Thank you, @wcarson! I could now get the session token. My question now is, what parameters you sent in the /authorize endpoint? Here, I am trying to do sso between an app (clientId = x) and a website (clientId = y). The test user I am using have access to both app and website. What parameters should I set in authorize and from what context?

gabrielmirandat avatar Jun 07 '21 15:06 gabrielmirandat

I got it to work! As said before, just calling with fetch already set the cookie, and solves the problem, now I am calling my website secured router directly. Thank you @wcarson

gabrielmirandat avatar Jun 08 '21 15:06 gabrielmirandat

@gabrielmirandat @wcarson Can you please describe how you did the Okta SSO from Mobile app to Web view ?

wb7212 avatar Jul 12 '24 16:07 wb7212