FormidableLabs/react-native-app-auth

Support for single sign-out

sattaman opened this issue ยท 19 comments

Currently signout is not ending the session with ID Server

http://docs.identityserver.io/en/release/endpoints/endsession.html#refendsession

https://openid.net/specs/openid-connect-session-1_0.html#RPLogout

Is this something I am going to need to achieve outside of this library?

config.serviceConfiguration.authorizationEndpoint = config.serviceConfiguration.revocationEndpoint
      const result = await this.appAuth.authorize(config);
  • and you need to add a fast patch for callback (return from browser)

soon you will see it on my fork of this library

Has anyone been able to make this work with Okta? I'm not sure how to access the Okta session Cookie in order to clear it when using the above workaround.

@kadikraman Support has now been merged into master of appauth ios https://github.com/openid/AppAuth-iOS/pull/259/files

@asherzog Did you manage to clear the session when revoking Okta auth -- in particular, on Android?

I'm still getting the password field only, and if the user refreshes & clicks the 'Log Out' link there, then logs in again, it doesn't follow the callback to return the new user creds.

I tried clearing cookies with https://github.com/joeferraro/react-native-cookies, but that seems to have no effect.

@spsaucier Nope, not with app-auth...

We ended up making our own bastardized flow that involves using Okta's inline hooks (https://developer.okta.com/docs/concepts/inline-hooks/) to help track the session ID and then built our own separate api around their session endpoints (https://developer.okta.com/docs/reference/api/sessions/#close-session) to revoke the user's session.

Pretty messy and I don't really recommend it, but it works for us I guess....

@asherzog so not using react-native-app-auth at all, then? That's a bummer. Thanks for the tip.

@kadikraman is there any way that user can "logout" from the app? I was trying to revoke your token access and send another authorize with extra config additionalParameters: {prompt: 'login'}, but when a log-in again i got an error with message "Response state param did not match request state".

No further info about this? Revoke/logout does not work with Cognito (even when additionalParameters used) and as commented, cookies can not be deleted with react-native-cookies.

@kaduelinho and others trying to solve this problem with Cognito.

We implemented a workaround in a way that in logout call authorize with different config than in login. In logout use config with authorization endpoint set for 'authorizationEndpoint: '<YOUR_DOMAIN_NAME>/logout'. This forces the app to the cognito login screen and deletes cookies from the browser.

@iaaltojarvi Good workaround. except that, called with the same parameters as 'authorize', it will redirect to Cognito's login form first, before redirecting to the application's screen. That's an inconvenience in my case. Have you worked around that somehow?

@snicro Sorry, don't have answer for that. Cognito login form was the solution we needed.

@kadikraman AppAuth-Android also implemented this feature. Now it's time to support RP-initiated logout? openid/AppAuth-Android#525

I'm having issues with Okta sign-out as well.

I've tried the workaround using authorize() with config.serviceConfiguration.authorizationEndpoint set to https://subdomain.okta.com/oauth2/default/v1/logout, and

additionalParameters: {
  id_token_hint: idToken,
  post_logout_redirect_uri: 'reversed.app.domain:/callback'
}

Which mostly works. It does sign the user out and clears the Okta session cookie, but then the AppAuth callback fails and crashes the app in Android with the following:

java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=0, result=-1, data=Intent { dat=creversed.app.domain:/callback?state=asdfasdfasdf (has extras) }} to activity {reversed.app.domain/com.app.MainActivity}: java.lang.IllegalStateException: authorizationCode not available for exchange request

Wrapping the await authorize() call in a try catch does not prevent the crash.

Aaaand after some investigation into AppAuth-Android I realized that the callback has no exception handling to forward to the promise, but I just fixed the crash by adding skipCodeExchange and usePKCE config options:

const logoutConfig = {
  clientId: OKTA_CLIENT_ID,
  redirectUrl: OKTA_CALLBACK_URI,
  scopes: [],
  serviceConfiguration: {
    authorizationEndpoint: `${OKTA_TENANT}/v1/logout`,
    tokenEndpoint: `${OKTA_TENANT}/v1/token`
  },
  additionalParameters: {
    id_token_hint: idToken,
    post_logout_redirect_uri: OKTA_CALLBACK_URI
  },
  skipCodeExchange: true,
  usePKCE: false
};

@kaduelinho and others trying to solve this problem with Cognito.

We implemented a workaround in a way that in logout call authorize with different config than in login. In logout use config with authorization endpoint set for 'authorizationEndpoint: '<YOUR_DOMAIN_NAME>/logout'. This forces the app to the cognito login screen and deletes cookies from the browser.

This worked for us for Cognito. I think you can do even better by simply always using <YOUR_DOMAIN_NAME>/logout as the authorization endpoint, no need for separate login and logout configs. Use your config but replace /oauth2/authorize with /logout.

If the user isn't signed into Cognito, /logout will actually take them to the login screen. The RN logout button effectively becomes a no-op. Then when the user wants to log in again, they'll be taken to /logout which will delete the Cognito cookies and take them back to /login, where they can enter new credentials or click on an IdP.

It doesn't actually delete cookies from the individual IdP's (we use social login) but at least it gets them back to a Cognito login screen.

Using authorize() with an end session endpoint in place of the authorization endpoint is not acceptable or intuitive to the user as it prompts with " would like to use to login" when the user taps the logout button and is followed by a browser window appearing momentarily. Is there a way to implement an endSession method with no popups or modals?

Did you ever find a solution, @cooper ? I'm experiencing the same problem with the modal opening for signing out

Closing as we provide various options for logout and ephemeral sessions. Support is dependent on the IDP itself, which we do not control.

@kaduelinho and others trying to solve this problem with Cognito.
We implemented a workaround in a way that in logout call authorize with different config than in login. In logout use config with authorization endpoint set for 'authorizationEndpoint: '<YOUR_DOMAIN_NAME>/logout'. This forces the app to the cognito login screen and deletes cookies from the browser.

This worked for us for Cognito. I think you can do even better by simply always using <YOUR_DOMAIN_NAME>/logout as the authorization endpoint, no need for separate login and logout configs. Use your config but replace /oauth2/authorize with /logout.

If the user isn't signed into Cognito, /logout will actually take them to the login screen. The RN logout button effectively becomes a no-op. Then when the user wants to log in again, they'll be taken to /logout which will delete the Cognito cookies and take them back to /login, where they can enter new credentials or click on an IdP.

It doesn't actually delete cookies from the individual IdP's (we use social login) but at least it gets them back to a Cognito login screen.

@wafisher This has been a huge help thank you! This worked for us.

I was also using Cognito and we were trying to replicate the behaviour of forcing the user to login each time. We couldn't replicate this with 'login: prompt' being passed to react native app auth. We also tried using logout using an endSessionEndpoint but that also didn't working. Using the /logout as the authorizationEndpoint.

Thanks again.