Reputation: 660
I am writing a dashboard like web application. Status changes of external systems should pushed down to the browser via SignalR. The external systems send their updates to Azure Service Bus topics. I have written an Azure Function which will be triggered by one of the topics. The function connects to the SignalR hub via the SignalR .Net Client library and forwards the message to the hub. The hub then sends the message to the browsers.
For now this works fine. The next step is to enable authentication for the SignalR hub. Other parts of the web app require authentication. The user logs in with his Azure AD credentials.
The question is how can the Azure function authenticate against SignalR? Saving some credentials in the app settings of the Azure Function App is a no go.
I have researched a workaround with the scale out technique of SignalR. We can configure a Service Bus Topic as a backplane. Each SignalR hub sends a copy of the message into the topic such that other instances of the hub get the message and push it down to their connected clients. The idea was that the Azure function pushes the status information into the backplane topic. But sadly SignalR uses an unknown encoding. So this workaround is not possible.
Details to @astaykov's answer
Add an app role to the SignalR's app registration.
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"displayName": "Access SignalR Backend",
"id": "239de039-e2c5-445c-8454-ccdc51888b94",
"isEnabled": true,
"description": "Allow the application to access SignalR Backend.",
"value": "access"
}
],
Create a key in the Azure Function App's app registration and use it when acquiring the token.
var ctx = new AuthenticationContext(tenant);
var cred = new ClientCredential(functionAppRegistrationId, key);
AuthenticationResult result = await ctx.AcquireTokenAsync(signalRRegistrationId, cred);
Upvotes: 4
Views: 2494
Reputation: 30903
You formulate two questions. So I will tackle them separately.
The question is how can the Azure function authenticate against SignalR? Saving some credentials in the app settings of the Azure Function App is a no go.
As @GreameMiller already mentioned, you should look at authenticating the SignalR with OAuth Bearer Token. For your Azure Function App you can create a Service Principal in your Azure AD and use that to get a valid Token for your SignalR (which has to be anyway another Application in Azure AD, or the same as your web app). The latter you probably already done, you will need to get the former.
One very important thing - once you get both the "applications" (Service Principals) in your Azure AD you have to make sure that the "Function App Service Principal" has access to the "SignalR Web App" by explicitly granting those permission in the Azure AD Portal. Again from that article, you have to go to Configuration setting of your "Function App" application and make sure to configure "Permissions to other applications". If you have correctly configured your WebApp (with SignalR) you shall see that in the list of available applications for configuration with only option - Access Name of your app. You have to use Application Permissions
and not Delegated Permissions
.
Rest of the job is standard OAuth2 Client programming - client Id + client secret. But yes, you have to keep those in your Function App's function. Not sure how you imagine Function App can get a token without any kind of credentials.
Your second part
... The idea was that the Azure function pushes the status information into the backplane topic. But sadly SignalR uses an unknown encoding. So this workaround is not possible.
You are on the right path with using ServiceBus as a back plane for signalR. However, this is design to help synchronise all signalR hubs on a scale-out deployment (what typically cloud is all about), and not for your clients to push messages to the hubs. These are system messages used only by the signalR hubs to make sure that everyone knows everything. When going cloud and going scale - you need that back plane anyway.
Upvotes: 6