How to use serverless Azure SignalR (REST API / Upstream) with ReactJS? - node.js

On high level I want to achieve real time communication between two ReactJS apps. I need to be able to create specific groups to separate the end users, that group will belong to another group with one or more manager users. The manager should be able to send messages (can a be string or object) to the whole end user group or just for one user within that group, which upon I can act in the end user app. The end users should be able to send a message for the specific group of managers.
Since Azure Cloud is given, a sensible choice would be to use the Azure SignalR, especially because it has a serverless plan.
I have created the SignalR service, set it to serverless mode.
Installed #microsoft/signalr package to the React apps.
Created a Nodejs negotiate HTTP triggered function with signalR binding.
At this point I'm connected to signalR. But I'm confused how to proceed.
On one hand I should be able to use SignalR REST API, on the other hand I could use SignalR Upstream. Upstream seems more suitable, since users can invoke hub methods (in my case Nodejs SignalR bindings in the Function App) and users gets notified when client connections are connected or disconnected. That is important for the manager users to see who is connected and if the connection is still alive. As next steps:
defined Upstream URL
created connected/disconnected bindings in the Function app
function.json:
{
"bindings": [
{
"type": "signalRTrigger",
"name": "invocation",
"hubName": "default",
"category": "connections",
"event": "connected",
"direction": "in"
},
{
"type": "signalR",
"name": "signalRMessages",
"hubName": "default",
"connectionStringSetting": "AzureSignalRConnectionString",
"direction": "out"
}
]
}
index.js:
module.exports = function (context, invocation) {
context.bindings.signalRMessages = [
{
target: "connected", // name of the client method to invoke
arguments: [invocation.ConnectionId],
},
];
context.done();
};
In similar manner sending a broad cast message:
{
"bindings": [
{
"type": "signalRTrigger",
"name": "invocation",
"hubName": "default",
"category": "messages",
"event": "broadcastMessage",
"parameterNames": ["message"],
"direction": "in"
},
{
"type": "signalR",
"name": "signalRMessages",
"hubName": "default",
"connectionStringSetting": "AzureSignalRConnectionString",
"direction": "out"
}
]
}
module.exports = function (context, invocation) {
context.bindings.signalRMessages = [
{
target: "broadcastMessage", // name of the client method to invoke
arguments: [
context.bindingData.message, // arguments to pass to client method. binding with parameterNames
],
},
];
context.done();
};
After connection from the React app, the connected method is fired automatically and I could invoke other methods like: siglarConnection.invoke("broadcast", 'Hi')
But this is as far as I got. No private message, no user groups and still need to manage the active connections somewhere.
Also there is a suggestion, that I could use userId to send messages directly, no need to bother with the connectionId. Since other functions are using App Service Authentication and the users are stored in AD B2C:
enabled the App Service Authentication for the Function app
Now for the React apps to connect I need to pass an access token with to the connection builder else I get a 401. Now I can apps connect again but now using the authenticated users access token, which is a good thing, but because of this my invokations does not work anymore. Most likely because I cannot supply access token with these and I get back 401.
Security is a must, so I decided to take a look at the REST API way.
Looks fairly straight forward, I need to call the specified endpoints, but calling them actually gives 401 response www-authenticate: Bearer error="invalid_token", error_description="The signature key was not found". Figures since I call the signalR service directly, providing AD B2C access token does not help. I probably need the access token from the negotiate, but I don't know how to get it. Sure enough it's in the negotiate response, but I was not able to intercept that.
Sorry for the lengthy description, but I believe it was necessary to understand my scenario. I may have a major overlook somewhere or someone with similar experience can clear up the confusion. There are tons of examples using C#, but I cannot use that.
Any help is appreciated.

Related

adal:tokenRenewFailure, code: invalid_resource|AADSTS500011

I'm trying to build a simple Teams tab app that lists the members of a team. I've used the Teams Toolkit for VS Code to generate the boilerplate. Running the app using F5 works fine. So far, so good.
Next I'm trying to read the team members from Graph. I've read about RSC (resource-specific consent) which seems to be exactly what I need. Because I want to prevent the app from opening any permission popups or login popups (other than the one appearing during the installation).
So I've followed the guide https://learn.microsoft.com/en-us/microsoftteams/platform/graph-api/rsc/resource-specific-consent and I've also made the check. Works fine.
However, as soon as I'm running the code locally (using F5), I'm getting this error:
AUTHMSAL: Event: adal:tokenRenewFailure, code: invalid_resource|AADSTS500011: The resource principal named api://localhost:53000/MY-CLIENT-ID-UUID was not found in the tenant named MYTESTTENANT. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You might have sent your authentication request to the wrong tenant.
I've double checked: the tenant does exist (and there's only this one). The app id is also correct, it resembles the one I've added using the "App registration". I've also added a "Client secret", however I'm not exactly sure where to add it to my code. This is probably the root cause of my problem.
The relevant parts of my code are:
// manifest.template.json
{
...
"webApplicationInfo": {
"id": "MY-CLIENT-ID-UUID",
"resource": "api://localhost:53000/MY-CLIENT-ID-UUID"
},
"authorization": {
"permissions": {
"resourceSpecific": [
{
"name": "TeamSettings.Read.Group",
"type": "Application"
},
{
"name": "TeamMember.Read.Group",
"type": "Application"
},
// ... (I've added *all* other permissions, too, just for testing...)
]
}
}
}
// Tab.tsx
// ...
// I've read on NPM that useTeamsFx() is deprecated and switched to useTeamsUserCredential()
const all = useTeamsUserCredential({
clientId: "MY-CLIENT-ID-UUID",
initiateLoginEndpoint: "fooBarInitiateLoginEndpoint",
// ...don't I have to add my clientSecret somewhere?
});
// Welcome.tsx
// ...
const { loading, error, data, reload } = useGraphWithCredential(
async (graph, credential, scope) => {
await graph.api(`/teams/MY-GROUP-ID/members`).get() // leads to the error
},
{
scope: [
"TeamMember.Read.Group"
],
credential
}
)
I've also tried to follow the AddSSO guide, but it led to permission popups which I want to prevent. Plus it added a lot of AAD specific stuff (like aad.template.json), which I don't need, because RSC suffices in my case (...right?).
Also, my app doesn't need SSO (...right?) because it only lists the members of the team and it runs inside Teams only...
EDIT
I've also tried new TeamsFx(IdentityType.App) instead of useTeamsUserCredential() (because RSC permissions have "type": "Application" in the manifest.template.json), however this ended up in an error:
Uncaught ErrorWithCode.IdentityTypeNotSupported: Application identity is not supported in TeamsFx
Somebody else may be able to provide you a full Teams example, but the main error in your case is this one:
AUTHMSAL: Event: adal:tokenRenewFailure, code: invalid_resource|AADSTS500011: The resource principal named api://localhost:53000/MY-CLIENT-ID-UUID was not found in the tenant named MYTESTTENANT. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You might have sent your authentication request to the wrong tenant.
The reason for this is here:
"webApplicationInfo": {
"id": "MY-CLIENT-ID-UUID",
"resource": "api://localhost:53000/MY-CLIENT-ID-UUID"
},
"api://localhost:53000/MY-CLIENT-ID-UUID" is not a valid resource identifier. Please note that this is not the API url, but rather its identifier. Please look for the App Id URI in your application registration in Azure Portal.
The correct value is most likely api://<your-client-id>, but you need to set it first.
See also Does the resource URL in webApplicationInfo need to contain the Microsoft Teams App ID?
https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/Overview/appId/<your-client-id>/

Stripe apis return empty data when connected over Extension OAuth

I have implemented an app that uses Stripe Oauth implementation, after following the instructions in the building extensions
Authentication is done perfectly. I'm able to retrieve access token and other details.
{
"access_token":"sk_test_51KHr6dAuxxxx",
"refresh_token":"rt_KxmgQFvxxxx",
"expires_in":1642171943,
"livemode":false,
"stripe_publishable_key":"pk_test_51KHr6dxxx",
"stripe_user_id":"acct_1KHrxxxx"
}
Now the problem comes when trying to get resources from Stripe. If an API call is made to https://api.stripe.com/v1/customers, an empty data is returned.
{
"object": "list",
"data": [],
"has_more": false,
"url": "/v1/customers"
}
At the same time, if customer "key (secret test mode API key.)" is used, that endpoint return 4 customers (all of them).
So clearly, the access token received after OAuth is missing something.
Also tried adding the Stripe-Account key and customer account id in the headers, and received the following error.
{
"error": {
"code": "platform_account_required",
"doc_url": "https://stripe.com/docs/error-codes/platform-account-required",
"message": "Only Stripe Connect platforms can work with other accounts. If you specified a client_id parameter, make sure it's correct. If you need to setup a Stripe Connect platform, you can do so at https://dashboard.stripe.com/account/applications/settings.",
"type": "invalid_request_error"
}
}
I suspect something might be wrong with the app itself, but not sure :D
EDIT
Adding a few tried items using composer require stripe/stripe-php
\Stripe\Stripe::setApiKey("sk_test_51KHxxx");
return \Stripe\Customer::all()
$stripe = new \Stripe\StripeClient('sk_test_51Kxxx');
return $stripe->customers->all(['limit' => 30]);
This error typically occurs when you try to make a request from an account that is not a platform account i.e. it has no Connected accounts.
Looking at your code snippets, I'm guessing that you're making the request with the connected account's secret key since the first few characters are the same.
When making Connect requests, you should be using the API key that belongs to the platform account and then provide the optional stripe_account parameter [0].
\Stripe\Stripe::setApiKey("PLATFORM_SECRET_KEY");
$customers = \Stripe\Customer::all([],["stripe_account" => "CONNECTED_ACCOUNT_ID"]);
[0] https://stripe.com/docs/connect/authentication

Azure AD integration with Bot Framework / teams

Last week I've been looking at Bot framework Samples, honestly BotFx isn't my area of expertise.
I was playing with these samples from the sample library:
18.bot-authentication
24.bot-authentication-msgraph
46.teams-auth
The required steps for making work each of them are almost the same, for #18 and make it work in the emulator this include:
Register the BotApp in Azure AD
Generate a Secret
Add the Redirect URI (as documented it should be: https://token.botframework.com/.auth/web/redirect)
Create an azure bot service
Customize the OAuth Connection Settings
Then in the solution Modify appsettings.json (sample values below)
{
"ConnectionName": "juank",
"MicrosoftAppId": "cee1234562074c-1b3e-49b4-9e76-b727d73453454e018d",
"MicrosoftAppPassword": "uxPdfgwo.JAYmgrtU]w5I7KdgxLZSJ.a[qtgtrFxYZ02"
}
After that It's required to run the emulator and configure the
following settings
Up to this point the bot works as expected
Then I type any... and it just doesn't work. I receive this answer
from the bot :
And this data from the trace Operation returned an invalid status
code 'Unauthorized'
{
"channelId": "emulator",
"conversation": {
"id": "77631280-22e8-11ea-93e0-6dc9b0b41a7c|livechat"
},
"from": {
"id": "61bab030-214b-11ea-9cf4-193735472c4b",
"name": "Bot",
"role": "bot"
},
"id": "ae429e60-22e8-11ea-9786-a543cb22378b",
"label": "TurnError",
"localTimestamp": "2019-12-20T00:22:13-05:00",
"locale": "en-US",
"name": "OnTurnError Trace",
"recipient": {
"id": "f6982626-923e-4fd3-b930-eabf095e96df",
"role": "user"
},
"replyToId": "aacb51f0-22e8-11ea-9786-a543cb22378b",
"serviceUrl": "https://7eec83e4.ngrok.io",
"timestamp": "2019-12-20T05:22:13.958Z",
"type": "trace",
"value": "Operation returned an invalid status code 'Unauthorized'",
"valueType": "https://www.botframework.com/schemas/error"
}
And that's all.
I've successfully acquired the token from the OAuth setting Test tool in azure portal and also using Postman, but i haven't been able to make these Demos work properly once OAuthCard should be presented for login. Debugging hasn't been helpful since there isn't other information apart from JSON exposed above.
Any guidance or orientation about how to fix this will be appreciated.
There is no need to configure Azure Bot Service configurations in emulator. The Application Id and Application Password should be the same as those in appsettings.
And you should got these values from Azure portal under Configuration part.
Before doing this, please make sure the auth connection works.
Update:
You can change the Microsoft APPId here:

Is there a way to get user permissions in a specific Azure Devops Project using rest api?

Hi I want to check the permissions of a user in a specific Azure Devops Project. Is there a possible way to get it? As far as I know project level permission is different than organization level permissions. Thanks.
Already test some several rest apis but still I can't have the project level permission.
There is currently no out-of-the-box rest api to get the user's permission in project.
To achieve this demand, you can use this rest api :
https://dev.azure.com/{org}/_apis/Contribution/HierarchyQuery?api-version=5.0-preview.1
Request body:
{
"contributionIds": ["ms.vss-admin-web.org-admin-permissions-pivot-data-provider"],
"dataProviderContext": {
"properties": {
"subjectDescriptor": "msa.ZjE1ZTk0NmMtOTI4OS03Mjg5LTljMGUtMDIwMTdlYmM2Nzhj",
"sourcePage": {
"url": "https://dev.azure.com/xxx/xxxx/_settings/permissions",
"routeId": "ms.vss-admin-web.project-admin-hub-route",
"routeValues": {
"action": "Execute",
"adminPivot": "permissions",
"controller": "ContributedPage",
"project": "XXX",
"serviceHost": "0933e8b2-f504-4b7e-9e9e-xxxxx (xxx)"
}
}
}
}
}
You can track this rest api by press F12 in browser then select Network .Then looking for the record that response body included returned permission. From this record you can get the rest api and request body.
I tested with postman , with this api ,I can successful get user's permission in project. As shown below:

Creating Azure App Insights using REST API fails requires ROLE

I am generating API Key for an App Insight. I am using the URL
"https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Insights/components/{resourceName}/ApiKeys"
I don't have any clear documentation and I found this from the MS SDK:
https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/applicationinsights/Microsoft.Azure.Management.ApplicationInsights/src/Generated/APIKeysOperations.cs
However, when I try to generate by mentioning a "name", an error comes in response:
{
"code": "The API Key needs to have a Role",
"message": "The API Key needs to have a Role",
"innererror": {
"diagnosticcontext": "e1f66da1-9247-459e-a519-6426fa1449d1",
"time": "2019-09-20T07:48:20.2634617Z"
}
}
My POST body is as following:
{
"name": "asimplekeyname"
}
Please help if someone has used this specific API.
You need to include the following properties in the body.
{
"name":"test3",
"linkedReadProperties":[
"/subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/microsoft.insights/components/<appinsight-name>/api",
"/subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/microsoft.insights/components/<appinsight-name>/agentconfig"
],
"linkedWriteProperties":[
"/subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/microsoft.insights/components/<appinsight-name>/annotations"
]
}
The three properties correspond the ones in the portal -> your appinsight -> API Access -> Create API key.
api - Read telemetry
agentconfig - Authenticate SDK control channel
annotations - Write annotations
You need to select at least one of them, inculde in the request body.
For example, you just select the first one as below.
The body should be:
{
"name":"test3",
"linkedReadProperties":[
"/subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/microsoft.insights/components/<appinsight-name>/api"
],
"linkedWriteProperties":[]
}

Resources