When building solutions with Umbraco, there is regularly a need to surface information or functionality above and beyond the content managed in the CMS. Oftentimes this comes from an external service that you need to integrate into the website.
Currently, we could consider there being two extremes as to how you might go about it. On the one hand, of course, you can just do this yourselves with custom integration code. We have the full power of .NET under the hood of Umbraco, so armed with an HttpClient, a serialization library, and an API or client library provided by the service, you are off to the races. You have full control over the implementation, but you do have to do all the work yourselves.
At the other extreme, you might make use of a package that exists to provide the functionality you need, perhaps one that we've built at HQ. If you can find one that matches both the service you need to work with and the use case you have, you'll likely be able to save quite a bit of time by using one of these. Even if either the service or use case differs, most of these integrations, including all the HQ ones, are open source, so you at least have something to start from if you want to take advantage of it. This allows us to reduce the effort somewhat from having to do all the work yourselves.
Making authentication and authorization simpler
One thing we've discovered in building integrations is that many services require a similar, but not identical, process for authentication and authorization - using some form of OAuth flow. How to code up these flows is reasonably established, but they do take some effort and usually from a relatively senior developer.
You have to consider and implement quite a few things, including, but not limited to:
- Redirecting to an authentication endpoint.
- Handling the response including an authentication code and exchanging it for an access token.
- Securely storing the token.
- Including the token in API requests.
- Serializing requests and deserializing the API responses.
- Handling cases where the token has expired and obtaining a new one via a refresh token.
So we thought, what if we could create a package that can handle all this, for multiple services, with the subtle differences between how services implement their auth process handled by providing custom configuration? Maybe that way we can help with something in the middle of these two extremes - we take care of the plumbing, and you focus on implementing the specific business functionality you need from the external service.
And that's what I'm pleased to announce today, a new open-source package called Umbraco Authorized Services that you can use to help with building your own integrations.
How to use the package
To use it, you will need to create your own application with the third-party service. This will provide you with a client Id and secret that are necessary for the authorization flow.
The package is of course available on the Umbraco Marketplace and can be installed into your Umbraco application from NuGet.
<PackageReference Include="Umbraco.AuthorizedServices" Version="0.1.0" />
It's compatible with Umbraco CMS 10+.
You then need to provide configuration for the provider you want to integrate with. This will look something like the example below, which is a configuration we've been testing for working with the HubSpot contacts API. As you see, we need to configure not only things like the client ID and secret but also various hosts, paths, and options that define how the HubSpot authorization flow works as compared to other service providers. You also provide the permissions you need (in the form of scopes) and a sample GET request that can be used to verify the service is correctly set up.
"Scopes": "crm.objects.contacts.read crm.objects.contacts.write",
Via the backoffice, you'll find a new tree in the Settings section where the authorized services you have configured are shown.
Clicking on the service takes you to a screen where you can view the configuration, and trigger the authentication and authorization flow.
You'll be redirected to the provider to login, agree to the required permissions and the flow will complete, returning you to the backoffice and storing in a custom database table an access token for the API.
And with that, you can start using the API, by injecting a service defined by IAuthorizedServiceCaller and using the methods available. You can make requests using different HTTP verbs, and provide a path and typed parameters defining the request and response models.
Extension methods, analogous to those available on HttpClient, are also available to make the request syntax even less verbose.
In this example, we are retrieving a contact record from the HubSpot API, with the retrieval, refresh, and provision of the access token, along with serialization and deserialization, handled for you:
Overall the aim is to provide as simple as possible an API for interacting with the service, taking care of the plumbing code required for authentication and authorization, and leaving you to focus on using the service's API to implement the specific business logic you need.
Full documentation for the package is available at the Umbraco documentation website.
We worked iteratively on the development of the package, implementing it for one provider and then, when attempting a second, seeing what differences required additional configuration, and providing those. I'm pleased to say that it seems to work out quite well - we've established it now with more than 25 different SaaS services so can be reasonably confident it can generalize to others.
As the eagle-eyed readers may have spotted though, the currently released version is 0.1.0, with the "0" for the major version indicating that the status of the package is to an extent experimental. This purely reflects that it's new work, we expect to receive feedback from any early adopters using it in their projects and perhaps will require minor breaking changes in future developments.
The package is released as an open-source offering and is not covered by official Umbraco support arrangements, being directly maintained by the DXP development team. That said, we are keen to have feedback, hear of any issues, and will do our best to support anyone looking for advice in using the package.
How to get involved
The package is open-source on GitHub too where we've tried to document further not just how it's used, but also how it works, so if you want to dive into the innards you can too.
We'd be particularly keen to hear from anyone that used the package with services we haven't yet tried with. Assuming you can do so successfully, we'd really appreciate a PR to the Umbraco documentation repository that updates the page listing the configurations needed for the various services we've verified the package with.
You may find that you run into one of the subtle differences between the authorization flows that the package doesn't currently support. If that's the case, an issue, or even a PR with a suggested additional configuration or extension to support the service, will be happily received.
The hope is that via a joint HQ and community effort we can establish the approach as a real time-saver for developers looking to create integrations into Umbraco-based web applications, for a wide range of third-party services.