Disclaimer: This is a cross-post from my professional website. It's a tutorial for a product my company sells.
With AVACloud, you would usually use service based accounts to access the API. However, recently we've had an interesting use case: A client did the integration for AVACloud in an Excel AddIn, and for this, we wanted to go with individual Dangl.Identity user accounts instead of centrally managed OAuth2 clients. Since the default AvaCloudClientFactory from our Dangl.AVACloud package assumes that you're working with clients, you need to add some plumbing code to work with user accounts. It's pretty straightforward, but you need to follow a few steps to achieve it. So, here's how to do it:
We're first creating a class called UserAccountTokenHandler, which implements the ITokenHandler interface. This will try to obtain a Json Web Token (JWT) directly from AVACloud, with provided user credentials. It's used to replace the OpenID Connect based client credentials authentication flow used by default, and allows you to authenticate with AVACloud with a real user context. The implementation is pretty straightforward, getting a token is a single call to the AVACloud API.
We're then adding the TokenAccessChecker class, which just gets a token and checks if the user does have access to perform AVACloud operations. That way, we can show a notification in the UI if AVACloud access is denied, before waiting to see if service calls fail with a 403 - Forbidden status code response.
UserAccountHttpClientAccessor is a small utility class that's just a wrapper around HttpClient. We're using that to be able to provide a typed HttpClient with the HttpClientFactory pattern. We could also use named clients, but I usually prefer to wrap the Http client in a separate class.
Now that everything's set up, we want some more convenience. Working with REST APIs always has some overhead, like managing HttpClient lifecycle and ensuring each request is properly authenticated. Since I'm a big fan of using dependency injection, I usually create factory classes that can be used a singletons throughout the whole app lifecycle, and which do their internal service management. So, in our case, we're just initializing a single instance of AvaCloudUserClientFactory and then rely on it's internal service provider when we want to get a client class.
Finally, here's a test showing you a quick example that gets a token, checks if the user has access and then converts an Excel file using AVACloud: