Issues with OAuth Authentication in multi-region / multi-org environments

Hi All

To start with some (hopefully helpful) context, I'm developing for a client that has a presence in multiple regions and in some of those regions, they have multiple organizations.
We're building a single application using the SDK to handle day to day operations such as user creation (along with phones, assigning skills, groups, etc) and also reporting.

So to the problem:

I create an instance of the ApiClient and assign it things like the region, proxy, retryConfig, clientId, clientSecret, etc.

            // Sets proxy 
            var configOptions = new ApiClient.ClientRestOptions(){
                Proxy = new WebProxy(config.proxy, false, config.proxyBypassList.ToArray(), CredentialCache.DefaultCredentials)
            };

            // Sets automatic retries
            var retryConfig = new ApiClient.RetryConfiguration{
                MaxRetryTimeSec = 10,
                RetryMax = 5
            };

We iterate over our list of environments and instantiate a new ApiClient for each environment using those options as well as assign the clientId and clientSecret.

Now I want to make an API call, lets use UsersApi for this example.
So we instantiate the UsersApi and pass a Configuration object which contains our ApiClient.

Configuration configuration = new Configuration(apiClient);
UsersApi.Configuration = configuration;

At this point we still don't have an access token so we call

 UsersApi.Configuration.ApiClient.PostToken(clientId, clientSecret);

The access token gets stored in UsersApi.Configuration.ApiClient.Configuration.AccessToken

The problem with this is that the UsersApi looks for that access token in UsersApi.Configuration.AccessToken, so we get a 401 ApiException with 'no authentication bearer token specified in authorization header'. So the UsersApi does read the region and proxy settings specified in the ApiClient, just not the access token.

Ok, so we can code upfront to assign the access token from PostToken() to that field, but that only works once, in our case on app startup. When that token expires, our app should (in theory) break, unless we handle the ApiException.

BUT, ApiClient contains two functions that appear to be making the REST calls, CallApi and CallApiAsync - both of which checks for a 401 response and if so, calls function HandleExpiredAccessToken() to renew the token transparently in the background. Yet because it ultimately calls the same original function, PostToken, in ApiClient to renew that access token, it will never be stored in the correct UserApi.Configuration.AccessToken field, and calls will continue to return a 401.

Am I misunderstanding how the ApiClient works when used within the context of the UsersApi? Any advice or suggestions are appreciated!

It sounds like you're not u sing the configuration object when constructing the object. When you don't provide one, it uses the default singleton instance: platform-client-sdk-dotnet/build/src/PureCloudPlatform.Client.V2/Api/UsersApi.cs at master · MyPureCloud/platform-client-sdk-dotnet · GitHub

Edit: well, you are setting the Configuration property, which should have the same effect as using the constructor if you're using them in the same place (i.e. setting the config object on usersapi before calling posttoken). Could you provide a contiguous example of how you're constructing and using these objects? The 401 problem indicates the auth token isn't being set, so something in the code isn't wired up correctly.

Sure Tim, here's the snippet where we build our ApiClient and UsersApi

// ClientV2 is our ApiClient
// UserRequest is our UsersApi

foreach(var env in config.Environments){
   environmentsV2.Add(env.Key, env.Value);
   PureCloudRegionHosts region = GetRegion(env.Value.Url); // Gets the PureCloud region host for the client
    env.Value.ClientV2 = new ApiClient(){
         ClientOptions = configOptions,
         RetryConfig = retryConfig,
         ClientId = env.Value.ClientId,
         ClientSecret = env.Value.ClientSecret,
     };
    env.Value.ClientV2.setBasePath(region);
    env.Value.ClientV2.Configuration.ShouldRefreshAccessToken = true; //Should default to true anyway, this is just a precaution

    Configuration configuration = new Configuration(env.Value.ClientV2);

    env.Value.UserRequest = new UsersApi(configuration);
    env.Value.UserRequest.Configuration.ShouldRefreshAccessToken = true;
    env.Value.UserRequest.Configuration.ApiClient.PostToken(env.Value.ClientId, env.Value.ClientSecret);
 }

So just to reiterate, the PostToken function does retrieve an access token, but it gets stored in the ApiClient's Configuration.AccessToken which is not where UsersApi looks for the token when making a request.


Adding this in case it provides any additional insight.

This looks like it may be an issue with the SDK. I've tagged in the SDK team to take a look.

1 Like

This topic was automatically closed 31 days after the last reply. New replies are no longer allowed.