okta / okta-oidc-android

OIDC SDK for Android
https://github.com/okta/okta-oidc-android
Other
60 stars 45 forks source link

Problem changing an app from the org authorization server to a custom authorization server #294

Closed arctouch-ianribas closed 1 year ago

arctouch-ianribas commented 2 years ago

Problem

Updating our app to use a custom authorization server (https://myOrgDomain/oauth2/default) instead fo the org authorization server (https://myOrgDomain) to get tokens to send to our resource server doesn't work. It works on a fresh install but not when updating the app from a previous version that used the org authorization server.

It seems that the cached configuration on the device will not update to use the updated configuration provided with the new version of the app.

Investigation

Looking into the code in this repository, it would seem that this happens because the old issuer (https://myOrgDomain) is contained in the new issuer (https://myOrgDomain/oauth2/default), and the check to see if the cached configuration is still valid uses String#contains() (see AuthAPI.java, on the obtainNewConfiguration() method, around line 97):

            if (discoveryUri != null) {
                if (config == null || !discoveryUri.toString().contains(config.issuer)) {
                    mOktaState.setCurrentState(State.OBTAIN_CONFIGURATION);

Workaround

Our current workaround for this situation is to clear the configuration cache if we detect that the issuer in the current configuration is different from the new desired issuer, with a method like this:

    private fun clearConfigurationCacheIfNecessary(sharedPreferenceStorage: SharedPreferenceStorage) {
        val providerConfigurationKey = keyguardEncryptionManager.getHashed(ProviderConfiguration.RESTORE.key)
        val storedIssuer = ProviderConfiguration.RESTORE.restore(
            keyguardEncryptionManager.decrypt(sharedPreferenceStorage.get(providerConfigurationKey))
        )?.issuer

        if (storedIssuer != configuredIssuer) {
            sharedPreferenceStorage.delete(providerConfigurationKey)
            Log.i("OktaAuthService", "Cleared config: configuredIssuer=${configuredIssuer}, storedIssuer=$storedIssuer")
        }
    }

Where configuredIssuer is defined as: config.discoveryUri.toString().split("/.well-known")[0].

But this forced us to create and use a SharedPreferenceStorage instance ourselves when building an AuthClient, instead of relying on the default implementation, as we were doing originally.

NikitaAvraimov-okta commented 2 years ago

Thank you @arctouch-ianribas! for bringing this to our attention, and apologies for the delay. This issue will require additional investigation from our side, internal ref - 448925

FeiChen-okta commented 2 years ago

@arctouch-ianribas The user will have to sign in again when the authorization server changes. You can detect the org has changed and clear the data. Even if the new configuration is returned the existing tokens will be rejected since the issuer will be different.

arctouch-ianribas commented 2 years ago

I agree with what you say, @FeiChen-okta. And "detect the org has changed and clear the data" manually is what we ended up doing (see "Workaround" on the issue description). My problem with this approach is that it seems like something this library should be able to handle internally, without any app specific code.

Without the app specific code to clear the data, we have a strange and confusing situation where authentication works, authorization seems to work (with the old configuration, since we end up using the cached configuration) but the resource server keeps rejecting the tokens because it comes from the wrong issuer.

Furthermore, clearing the cached will be handled correctly with no app code needed if we change completely the org/issuer, for example when changing the authorization server from https://myOrgDomain to https://myNewOrgDomain.

JayNewstrom commented 1 year ago

This is now cached per org in the new SDK. We don't plan to make improvements to this SDK given the above work arounds.