Companion App Architecture
While the Power Platform, and more specifically Dataverse, is at the core of ecLearn, our product also leverages SCORM Cloud. SCORM Cloud offers a course player that supports many different e-learning formats, including xAPI, cmi5 and SCORM 1.2. We didn’t want to be in the business of keeping up to date with all the frequent changes that occur in e-learning formats, so we decided to use SCORM Cloud instead of building our own course player.
We interact with SCORM Cloud via an API, and some of that interaction needs to come directly from a learner’s browser. We don’t want to expose direct access to SCORM Cloud’s API to our users (we don’t want them to be able to access the entire API, nor do we want them to have access to our API keys), so instead we created a Companion App.
If you’re not already familiar with Companion Apps, check out our blog post or Portals Community Call on the subject. The very short summary is that a Companion App is a web service that you create and host yourself, outside of Power Pages, that you then interact with via JavaScript that exists on your Power Pages site. Power Pages supports this architecture by providing a way to securely authenticate with a Companion App.
Power Pages Token Service
To securely communicate with the Companion App, Power Pages offers a token service. You can use JavaScript on your Power Pages site to request a JWT token from the Power Pages web server. This token contains the ID of the contact that requested the token, and also includes the information necessarily to validate that the token was in fact created by Power Pages, and not spoofed by someone else – this information is called the signature.
Once you’ve requested the token from Power Pages, you can then pass this token as part of your requests to the Companion App. Then, before doing whatever the Companion App is supposed to, it should confirm the token validity using the signature. In this post we’re not going to get into the details of exactly how this is done, but what you need to know is that in order to validate that the token did in fact come from the Power Pages site, you need a key, known as the public key.
It’s called a public key because the public key is not a secret. Anyone can know what it is. That fact that the key is public doesn’t impact the security of the token, because the public key can only be used to verify where the token came from. A different private key is required to create the token to begin with. So knowing the public key of a Power Pages site allows you to verify if a token did in fact come from that site.
The public key for a site is available at the following URL:
https://yourportal.powerappsportals.com/_services/auth/publickey
While the private and public keys don’t change very often, a robust implementation shouldn’t rely on them remaining the same forever. This is why typically it is recommended to request the most up-to-date public key via code on a regular basis, rather than just hard-coding it into the Companion App. This is often done during the initialization of the app and then the key is cached for a short period of time, so that you don’t need to request it each time a token needs to be validated.
Not So Public Key
Requesting the public key via the above URL works great on public production sites. However, there is a problem if the site visibility is set to private. When a site is private, before accessing any of the URLs of a Power Pages site, you need to authenticate with Microsoft Entra ID. This is true even for the public key URL above.
It usually doesn’t make sense to complicate your Companion App with logic to authenticate via Entra ID just to get the public key, since usually this will only be a problem in pre-production environments. So what should we do?
This is where the answer we might give for a one-off project is different than as an ISV. In a one-off project, it might just be easiest to make the Power Pages site public. If the client is fine with that, then we’re good to go. However, since ecLearn is an ISV product meant for a large number of different clients with different policies, we need to be as flexible as possible.
In our case, we decided to allow the user to provide the Power Pages public key as part of the configuration. However, if the key was not provided, we would then use the above URL to request it. We recommend to our clients to leave that option empty if possible (i.e. if the site is not in private mode). That way, if their keys change, they don’t have to do anything. However, we also understand that different clients will have different rules about whether pre-production portals can be public or not. This allows us to support clients that want to use our product in pre-production environments where their Power Pages site is private.
Does the token coming from the oauth service work by default with Azure function auth. Or can it be set up to be that way?
I don’t think it works by default – you have to have the code in your Azure Function to validate the token.
Nick