Authorization denied for bot when attempting to create conversation via API - microsoft-graph-api

I'm trying to develop a bot to be used exclusively for proactive messaging (since unfortunately, it appears Connectors do not support direct messaging). I stood up a web service, and was able to receive the payload from Teams when I sent a message to the bot.
I'm now trying to send a proactive message from the bot back to my user, as described here. Per the instructions, I am POSTing the following payload to <serviceUrl>/v3/conversations. (Values in brackets are interpolated from the payload I received from Teams)
{
"bot": {
"id": <recipient.id>,
"name": <recipient.name>
},
"isGroup": false,
"members": [
{
"id": <from.id>,
"name": <from.name>
}
],
"tenantId": <channelData.tenant.id>,
"topicName": "News Alert"
}
I also included a Bearer token that I got by calling https://login.microsoftonline.com/<channelData.tenant.id>/oauth2/v2.0/token. Yet, whenever I try to create the conversation, it fails with an error that "Authorization has been denied for this request." As far as I can tell, the token should be valid, so I'm not sure what else could be going on here. I saw something about trusting the service URL, but I'm not sure how I would do that since I'm not using the Bot SDK. Perhaps I'm going about this wrong and should be trying to create an Activity rather than a Conversation?

There are basically two steps in sending pro-active messages. The first step is just a once-off - it's getting the unique ID of the conversation between the bot and the user. It's the paragraph you're linking to in your original question, and it's the payload sample you're showing. Once you've got that conversation id, you'd then proceed to sending messages at any time in the future (that's this paragraph).
However, in Teams, the first part is handled differently. Rather than calling the bot framework conversation endpoint (recall that bot framework is used for other things aside from Teams bots), you wait for the user to install the app, which includes your bot. When this is done, your bot will receive a conversationUpdate event. When this fires, you'll be sent a payload which includes the conversationId of the newly-created conversation. This replaces the call you're currently making.
You need to save the conversationId, and the serviceUrl (which will be similar too 'https://smba.trafficmanager.net/apis', but unique for Teams, and will be the 'base' of the URL you'll call later).
Importantly, it is possible to "pre-install" an app for a user, using the Graph API. See Install app for user.
That should help with what you're missing. However, as an 'fyi', you can use libraries for this instead of making the call directly yourself. In dotnet, for instance, you can reference Microsoft.Bot.Connector.ConnectorClient (in Microsoft.Bot.Connector), which has a Conversations.SendToConversationAsync(..) method.

I think I've figured out the problem. I sent my token request to https://login.microsoftonline.com/<channelData.tenant.id>/oauth2/v2.0/token, which was successful and gave me a token back. However, the instructions outlined here say not to use <channelData.tenant.id>, but instead just the hardcoded string botframework.com. After requesting the token that way, my requests appear to be working.

Related

How should Slack bot tokens be stored?

I'm building my first Slack bot and I've got the basics mostly working... sending API requests, receiving commands and events, etc. But the part I'm left a bit confused about is what I'm supposed to do with the "Bot User OAuth Access Token".
The token appears to be shared across teams/workspaces, but it is returned to be during authentication of individual users with a call to /oauth.v2.access. Currently I'm storing the returned credentials payload in a table that has three columns:
My app's internal user ID
The Slack user ID embedded in the payload as authed_user.id
The entire JSON payload itself (jsonb in postgres if you're curious)
This allows me to initiate new API calls for actions that take place in my app (find by internal user ID) and also for interactions within Slack (find by Slack user ID).
What has left me a bit puzzled is what the convention is for when a user interacts with my bot that hasn't added my app. This can happen when a person ("Jose") adds my app and then their colleague ("Mary") discovers it in Slack and views the home screen, sends it a message, etc.
In order to take some action, such as prompt for the user to install my app, I need a token. Of course I have a token for Jose but not for Mary. I also have Jose's team ID stored in my table and Mary's team ID as part of the incoming event. So technically I could do something like this to get a working token to interact with Mary:
select credential_json from slack_credentials
where credential_json->>'type' = 'bot' and credential_json->'team'->>'id' = :marysTeamId
... which would pull out the bot token I captured when Jose added the app. This works, but it feels very wrong. I suppose if I just stored bot tokens in a separate table that looked like this:
The Slack team ID embedded in the payload as team.id
A subset of the JSON payload (ex: access_token, scope, bot_user_id, etc but not authed_user)
Then it wouldn't feel so yucky. But the docs + API ergonomics don't suggest this is a common approach either. So I'm curious what others do. If I don't hear anything back, I suppose my plan is to break out the bot tokens into a team-centric table.
Thanks!
The basic concept of Slack apps is that they are installed per workspace, not per user.
So while it's true that the app's token is derived from the user who installed your app to a new workspace, most the apps function are available to all users of the workspace.
e.g. slash commands will work for every user in every channel
e.g. posts of your app will be visible to all users of the related channel.
Therefore the best approach for storing tokens usually is with a primary key of Slack Team ID, Slack User ID.
And just to clarify. You do not need a token to prompt a user to install you app. Every app can be installed from webpage hosted by you (with the "Add to Slack button") or directly from the App Directory.

Slack API missing_scope for bot requests

I am trying to set channel topics with a bot user token, but I'm getting the missing_scope error:
{
ok: false,
error: 'missing_scope',
needed: 'channels:write',
provided: 'identify,bot:basic'
}
It works if I provide the "OAuth Access Token" (instead of "Bot User OAuth Access Token") from https://api.slack.com/apps/:appId/oauth, but this is a poor solution because the message that gets printed in the channel says that the app installer set the channel topic, not the bot user.
But, the docs say that bots can call channels.setTopic with a bot token, and they don't need channels:write:
What gives? Are there different kinds of bot tokens? Am I doing something wrong? As far as I can tell, I cannot set additional permissions for my bot user.
It also says on the the same documentation page:
Only user tokens may use this method. Bot user tokens will not work.
And since it does indeed not work as you say I am guessing the mention of the bot token in the above table is a documentation mistake.
If you want to be 100% sure I would advise to ask the Slack team directly.

Slack API Opening a New DM (Scopes and Permissions)

I am attempting to open a DM (Direct Message) with an arbitrary user using the im.open Slack API call. I am sending it a user's user_id that I obtain through their clicking of a consent button in order to begin a series of questions. I am sending data to the Slack API successfully along with receiving data. I am getting the following response...
{
"ok": false,
"error": "missing_scope",
"needed": "im:write",
"provided": "identify,incoming-webhook,chat:write:user,files:write:user",
}
I have went into the application's page and changed the scope of the app (I am not the owner, but have been given collaborator permissions by my team lead (the owner)). These are the current permissions...
I apologize for the poor quality of the image. The scopes are as follows...
identify
incoming-webhook
chat:write:user
files:write:user
im:write
After this change, I am still getting the same response from the Slack API. The following is what I am sending them (it's my user_id, and I don't mind).
{
"user": "U94155Z43"
}
Any help is appreciated. Thanks.
I needed to use the bot token "xoxb" instead of the user token "xoxp" which I had used for all other slack api calls.

How can I add a user to organization in ASANA via API?

I'd like to add a new user to ASANA programmatically. I already have the OAUTH App and the user token.
Looking at the API I can't find a way to "create a new user".
Is it possible to create a new user simple via API?
Otherwise, is it possible to "invite" a new user via given email? Like from the UI where you can put the EMAIL and the system send an invitation link!
I tried with:
https://app.asana.com/api/1.0/workspaces/[WORKSPACEID]/addUser?user=[NEW USER EMAIL]
But I get a BAD REQUEST in response:
{
"errors": [
{
"message": "Could not parse request data, invalid JSON",
"help": "For more information on API status codes and how to handle them, read the docs on errors: https://asana.com/developers/documentation/getting-started/errors"
}
]
}
Thank you very much
I've never tried to do that specifically, but recently I did attempt to add members to a project through the API. There was nothing in the documentation about it, and I was told that it wasn't a supported API operation.
I would guess that if there's no mention of this feature in the documentation that it's also not supported for a similar reason.

Facebook OpenGraph API: Can I Silently Send a Request from One User to Another?

How do I send a facebook app requests from one mobile user to another using the Graph API?
I have looked at facebooks documentation but the only options I have found are to A) send an app to user message from the app (which I can't get working) or B) to use the request dialog, which doesn't seem to let me send a request to a single user.
FB has instructions for how to build a custom "Multi-Friend Selector" but apparently not for mobile.
I have tried using HTTP POSTing to
https://graph.facebook.com/%s?access_token= ...
with POST data set to
message='Test Message'
but I get
WWW-Authenticate: OAuth "Facebook Platform" "invalid_request" "(#2) Failed to create any app request"
I have also tried in the Graph API Explorer but I get the same thing.
I don't want to send these messages to users that have installed the app and I don't mind the user having to provide confirmation for the FBFrictionlessRecipientCache. Also, my app is in Sandbox mode, but I only need to send the requests to the other developers.
I am looking for anything that will let me do multi-friend selectors or ask for lives, or get help from a friend, like I see in several mobile games these days.
You can use presentRequestsDialogModallyWithSession from FBWebDialogs.
You must specify a "to" parameter to identify the recipient, and you must use the FBFrictionlessRecipientCache.
The "to" parameter identifies the recipient. It stops the select user dialog from appearing.
The first time you send the request to each recipient the user will have to grant permission. After that, the FBFrictionlessRecipientCache will allow the request to be sent relatively silently (a dialog pops up briefly and goes away by itself).

Resources