Create MS Teams chats with MS Graph (or PowerShell) - powershell

I'm currently trying to use Microsoft Graph to send a Microsoft Teams Chat message to a specific employee.
The idea behind that is that I want to be able to send chat messages using PowerShell, but for now, I'd be happy to get it done in Microsoft Graph first and build a PowerShell script afterward.
Important: I don't want to post a message to a Channel, only in a 1:1 chat.
What I've tried:
I'm able to get the current chats for my own user by using:
https://graph.microsoft.com/beta/users/{myid}/chats
If, however, I try that with a different user's id, I get a 401 (permission denied) error. I can't even see their current chats even though I have all available permissions.
In the error message, it says the following:
"User Id must match the API caller when called in delegated mode"
... but I don't want to use delegated mode since that'd mean I'm executing the commands as if I would be that user, and therefore couldn't create the chat message which I want in the first place.
It might sound rather confusing, so I hope you get what I mean.

To my knowledge, there's no way to send a message directly to the user without some kind of context. The problem becomes, for instance, where would the message appear, and who would it be from?
If you could deal with it being inside a Channel instead, then PowerShell is fine as you can set up a webhook to do this. I've done the same, from PS -> Teams a few years ago, so I assume it should still work. This article should help.
Alternatively, if you really want a "1-1" conversation, so to speak, you need to create and register a Bot, so that the message comes "from someone" to the user. This concept is called Pro-active Messaging and I've posted more about it here. However, coming purely from PowerShell it's going to be a LOT of work:
Create a Bot in Azure to get the App ID and Password. Technically this would be a non-existent Bot as there's no implementation, which means if the user were to reply it would go nowhere. This might be ok? You could possibly try build an Azure Function Bot in PowerShell, but not something I've done myself so can't advise (I've only used C# for Bots thus far)
Create a Conversation ID, and save it for later - again, a bunch of work.
Convert the code (e.g. from my post above) into PowerShell, referencing the relevant NuGet packages.
So, I'd recommend trying to find an approach using a Teams Channel rather, and messaging the user there, if you can manage that in your use case?
Unless all of this is irrelevant if you're trying to send on behalf of another user?

The term "Delegated" in this context refers to the type of permissions claims included in the OAuth token. There are two types; Application and Delegated.
There are two key rules when it comes to Application vs. Delegated scopes:
A single token may only contain a single type of scope. In other words, the token itself is either an Application or Delegated token, never a combination of the two.
The type of scopes applied to a Token is determined by the OAuth Grant you used to obtain it:
Authorization Code: Delegated
Implicit: Delegated
Client Credentials: Application
With regard to the List Chats (/chats) endpoint, only Delegated permissions are supported:
Delegated (work or school account): Chat.Read, Chat.ReadWrite
Delegated (personal Microsoft account): Not supported.
Application: Not supported.
There is a general rule of thumb when it comes to permissions in Microsoft Graph (I use 'general' here since there are a couple of exceptions in older endpoints): Delegated scopes that only apply to the current user end in Read or ReadWrite while those that apply to any user end in .All.
Since these two scopes (Chat.Read and Chat.ReadWrite) do not end in .All, and only Delegated scopes are supported, this tells you that the only Chats you are able to access are those owned by the currently authenticated User. In other words, you cannot read another User's chat messages via the API.
If you think about it, this makes a lot of sense. If you didn't have an authenticated User, who would the Chat message you sent be "from"? A chat message requires both a Sender and a Recipient.
For your scenario, there are a couple of possible workarounds from a Teams ChatBot to simply setting up a new User that you authenticate as and send messages to other Users from.

Related

Create Teams meeting by Microsoft Graph or other means

I'd like to create MS Teams meetings from another application.
The Teams application is running on the computer, outlook is not used though.
How would I accomplish this the best / easiest way without (much) user interaction?
As far as I can see, the best option would be to use the REST API to create a meeting using the api-URL https://graph.microsoft.com/v1.0/me/events.
If I can also create a meeting commandline or by COM objects or something else, I could do that, too.
So here would be what I did for research with graph so far:
I can log on to https://developer.microsoft.com/en-us/graph/graph-explorer and use my user to create meetings and get the response. To do that, I modified the permission to read / read-write the calendar. If I copy the access token and use it with a powershell Invoke-RestMethod, it also does what I want. I can do the same with Connect-Graph -Scopes "Calendars.ReadWrite". But it would show this big browser windows about the login as X.
I read about apps, but if I use the apps ID and so on to log in silently, it seems like I am not in the current user scope but in a process scope and that's different. At least I set the API permissions up to also have access to Calendars.ReadWrite via Microsoft Graph, but I get an Access denied error if I try to run the same New-MgUserEvent to create a meeting for the current user (that is running the local powershell).
If use the token with Connect-MgGraph, it displays the client and tenantID and the ContextScope is process, not current user, so that would fit.
If I understand it correctly, I could use the token to get another one for a user... (reference is this: https://learn.microsoft.com/en-us/graph/auth-v2-user )
If I use the Connect-Graph -ForceRefresh parameter (which I guess would do the same, the popup tells me I'm logged in as the current user (not process).
This is a bit odd, so before I try to use the rest api and fumble a bit around:
Can I use the example from the link to refresh the token to get a user token that has the rights that I defined (and be able to access the calendar)?
Or is there some misunderstanding on my part?
Would it be a better idea to just use something like powershell, have the user log in once per day and leave the process in the background and create the new entries from there?
Do you have to refresh a token when you use connect-graph? Or could that be done better by Rest web api, if I can export the token?
The idea of having an app that would have access to all calendars would seem like a bigger security risk and I'd kind of want to avoid that. If I could configure the apps to have access to only one specific calendar, that would be cool, too. But I did not find it when looking around.
Thanks and best regards to all that took their time to read and consider to help.

Office 365 room mailboxes CalendarProcessing access via Microsoft Graph

When using rooms and equipments, Exchange (in Office 365, but in other versions as well) uses a number of options to handle requests for those resources in events.
By default, Exchange will for instance strip the subject when creating the event in the room's calendar, and replace it with the organiser name. If you then try to fetch the room's calendar (for a meeting room display, for instance), you'll only have the organiser name instead of the subject of each meeting.
This may be appropriate in some scenarios, but in many others one wants the actual subject to be shown in that calendar.
To achieve that, the only option I know of is to use the Powershell Set-CalendarProcessing cmdlet to change DeleteSubject, AddOrganizerToSubject and more.
In a SaaS environment this is pretty annoying as you need the Office 365 admin to use Powershell to do this operation, which may not be completely straightforward, or you need to ask for the user's login and password and pass them to Powershell, which raises security issues, and will not work in many scenarios (2FA, SAML auth...).
Is there a way to access these settings via Microsoft Graph?
Alternatively, if not available via Microsoft Graph, is there a way to use a Microsoft Graph oAuth token to perform this operation via Linux Powershell? I know it's possible to use oAuth tokens, but despite all my efforts I haven't managed to find a way to perform regular hosted oAuth login and use the token received for this purpose.
Any hints welcome!
Edit
To clarify: I'm in a SaaS scenario where I am the SaaS provider, so I need to allow admins of my customers to change those settings easily or automatically, it's not to access my own room mailboxes (I would use powershell for that).
I don't see anything in the MS Graph Reference that would do what you want. With that said, the barriers you state in your question for using the remote powershell api shouldn't be hard to accomodate.
For starters, your IT provider for email should work with you to configure rooms the way that you want/need. If they are willing to delegate this to you, then there are ways to set up Role Based Access Control (https://4sysops.com/archives/create-custom-rbac-roles-in-exchange-and-office-365/) to give you only access to calendar processing.
Likewise, MS has posted instructions and tools to use MFA with Exchange Online Powershell (https://learn.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/mfa-connect-to-exchange-online-powershell?view=exchange-ps).
According to your description, I assume you want to get the subject of a meeting room.
There is no reference on official Doc for your case yet, we can post this issue to the Graph support on the User Voice.
The only interface I'm aware of for managing this (beyond the Exchange UI of course) is PowerShell.
This isn't supported by Microsoft Graph or Exchange Web Services. It's worth noting that even if this operation was supported, it would still require an Admin to execute it. Operations of this nature almost always require Admin Consent.
Try using JEA (Just Enough Administration) or PSSessionConfigurations . Create a constrained endpoints and give access for necessary user/groups for required cmdlets.

Authentication needed when chat bot conversing with user

This got stuck in my head from many days, can anyone help or say at-least this is not at all possible?
I'm working on developing a chat bot using dialogflow which integrates multiple applications along with google home assistant, dialogflow, actions on google and an application which i want to manage using chat or voice commands. Until now its good and got amazed of features providing by google.
But i'm expecting one more feature. Don't know whether any alternatives available for this or not, but i tried exploring and reached to desert. Below are my requirements, if others think this is really unique and useful to them as well then i can say they are improvements or add-ons i'm expecting from DialogFlow.
Let's take an example of a chat bot which is serving users through google assistant and as a web bot as well. Now while conversing, intents may trigger web-hook in fulfillments which may require an authentication like OTP(Nope if anyone thought it for payments) which means registered users or limited users only can perform actions. This is same as we use roles and groups in all the applications.
The way google is sending google prompt to the user for logging into gmail, is there any way that we can collect PIN or OTP or PASSWORD through some notification sent to the users phone as some card's or input box like and html while conversing with chatbot through web or home assistant etc..., so that it helps in adding more security.
I recently worked in a chatbot project where I had to authenticate my users. I'm writing an article about it, but I'll tell you what I did:
First of all, I'm using OAuth 2.0 protocol to authenticate my users, but if you doesn't use OAuth, there's no problem, you could do something equivalent.
I'm using Authorization Code Grand flow.
Let's see the steps:
Step 1 - Authorization Url:
My bot generates an authorization url which contains all needed data to identify the conversation in callback moment. Like this one:
https://authorization-server.com/oauth/authorize
?client_id={your-client}
&response_type=code
&state={conversation_id: 123456789}
&redirect_uri={your-callback-url}
Notice that the state parameter contains the conversation_id which identifies your conversation, this state parameter will be back when users return to your handler.
Step 2 - User Authentication
When users click in this link, they'll be redirected to your login page at your authorization server.
Step 3 - Callback
After users get authenticated, they'll be redirect back to your handler (an endpoint which will receive the authorization code from authentication server and the state parameter).
When it received this authorization code, it'll be exchanged by an access token in authorization server.
Step 4 - Store token
In the final step, you already has an access token and the conversation_id parameter, you can store it in a database, in a cache or be stateless. Your rules!
In my case, I'm using Watson Assistant with Cloudant database, and I store those access tokens in my database. So, when users request something to my bot, it could get this token from database and pass to my back-end servers.
This kind of approach, I call "magic link". And you could improve it by shortening the url as bit.ly does.
I hope it could help you, feel free to ask me if you need.
Best
You probably don't want to implement the OTP scheme yourself. While you could do this, there are other systems already in place that will do this for you.
The best is the one that you reference - Google Sign In.
Fortunately, you can leverage Google Sign In for both your website (where you would get the user to sign in and then pass this information along as you do the Dialogflow calls) and for the Assistant (where Google will pass along an ID token, indicating it has authenticated the user).

is there a deep dive on google's oauth2 scopes?

I'm looking for some deep down detailed information on google's use of oauth scopes
My Drive app is working, so I get the simple use of scopes. However I have the following detailed questions/issues..
I specify scopes twice. Once in my app and then also in the API
Console. What is the respective significance of these two scope
declarations?
If I remove scopes, must my user re-authorise my app, or is this
only required for adding additional scopes?
If the answer to 2, is 'I can't silently remove scopes', will the
Google libraries deal gracefully with re-authorising the user, or
will I just get 403 failures? I've read How should an application add/remove scopes to an existing grant? but the accepted answer specifically references adding scopes, whereas my question is about removing scopes.
Can different modules within my app request different scopes within
the superset specified in the API console? To explain, my app has 3
components: a chrome extension accessing Drive, a web client using
JS to access Drive and YouTube (in online mode), and a server
component which accesses Drive (in offline mode)..
Can my app. enquire what scopes it has been granted?
A general question, I'm sure I face the same dilemma as many app authors. If I increase functionality (a good thing since it attracts users), I also need to increase permissions/trust a user places in my app (a bad thing since it repels users). Are there any recommendations on how apps should best handle this conflict of interests?
List of scopes in your client code - this is what a user authorizes your app to do
When you request authorization from a user, you need to specify what you would like the user to consent to. This is what the list of scopes is used for - it controls the text the user sees when they authorize your application, and the refresh / access tokens granted by that authorization are limited to making API calls that are allowed by those scopes.
List of enabled services in the API Console - this is what your app authorizes users to do
To my knowledge there is no list of scopes specified in the API Console. There is however a list of Google services that can enabled. Enabling/disabling a service here is more about turning on/off ability to make API calls and managing quota and/or accepting terms of service related to that API, than it is authorization.
When an API call is made - you send along an access token
The access token encapsulates the user making the request, the scopes the user authorized you for, and the client ID used for the authorization (which in turn belongs to your project). At this point you need to have the service that the API call is sent to enabled on the project, and the correct scope for the API request - or you will get a 403.
When your list of required scopes changes - you should expect users to need to re-authorize
At the point you request an access token (typically by sending a refresh token) you need to be prepared for that request not to succeed. Maybe it's because you've added scopes - but maybe a user has chosen to visit https://accounts.google.com/IssuedAuthSubTokens and has revoked your applications access. I'm not sure whether if you request less scopes than was granted by the user initially will trigger this, I would experiment to test - but the point is that regardless your code needs to be able to handle this scenario. I believe the OAuth2DecoratorFromClientSecrets (from the linked question) will handle this gracefully for you but am not certain - it should be easy enough to verify.
Using the same authorization across multiple clients - suggest reading through this doc and see if it covers all of your scenarios: https://developers.google.com/accounts/docs/CrossClientAuth
To see scopes granted to an access token - use the OAuth2 API: https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=yaxxxxxxxxxxxxxxx

How to use the same facebook application for different websites

I'm developing a small CMS in PHP and we're putting on social integration.
The content is changed by a single administrator who as right for publishing news, events and so on...
I'd to add this feature, when the admin publishes something it's already posted on facebook wall. I'm not very familiar with facebook php SDK, and i'm a little bit confused about it.
If (make it an example) 10 different sites are using my CMS, do I have to create 10 different facebook application? (let's assume the 10 websites are all in different domains and servers)
2nd, is there a way for authenticating with just PHP (something like sending username&password directly) so that the user does not need to be logged on facebook?
thanks
You might want to break up your question in to smaller understandable units. Its very difficult to understand what you are driving at.
My understanding of your problem could be minimal, but here goes...
1_ No you do not create 10 different facebook application. Create a single facebook application and make it a service entry point. So that all your cms sites could talk to this one site to interact with facebook. ( A REST service layer).
2_ Facebook api does not support username and password authentication. They only support oauth2.0. Although Oauth is not trivial, but since they have provided library for that, implementing authentication is pretty trivial.
Please read up on http://developers.facebook.com/docs/.
Its really easy and straight forward and well explained.
Your question is so vague and extensive that it cannot be answered well here.
If you experience any specific implementation problems, this is the right place.
However to answer atleast a part of your question:
The most powerful tool when working with facebook applications is the Graph API.
Its principle is very simple. You can do almonst any action on behalf of any user or application. You have to generate a token first that identifies the user and the proper permissions. Those tokens can be made "permanent" so you can do background tasks. Usually they are only active a very short time so you can perform actions while interacting with the user. The process of generating tokens involves the user so that he/she has to confirm the privileges you are asking for.
For websites that publish something automatically you would probably generate a permanent token one time that is active as long as you remove the app in your privacy settings.
Basically yuo can work with any application on any website. There is no limitation. However there are two ways of generating tokens. One involves on an additional request and one is done client side, which is bound to one domain oyu specifiedin your apps settings.
Addendum:
#ArtoAle
you are right about every app beeing assighend to exactly one domain. however once you obtained a valid token it doesnt matter from where or who you use it within the graph api.
let me expalin this a little bit:
it would make no sense since it is you doing the request. there is no such thing as "where the request is coming from". of course there is the "referer" header information, but it can be freely specified and is not used in any context of this.
the domain you enter in your apps settings only restricts where facebook redirects the user to.
why?
this ensures that some bad guy cannot set up a website on any domain and let the user authorize an app and get an access token with YOUR application.
so this setting ensures that the user and the access token are redirected back to YOUR site and not to another bad site.
but there is an alternative. if you use the control flow for desktop applications you don't get an access token right after the user has been redirected back. you get a temporary SESSION-TOKEN that you can EXCCHANGE for an access token. this exchange is done server side over the REST api and requires your application secret. So at this point it is ensured that it is YOU who gets the token.
This method can be done on any domain or in case of desktop applications on no domain at all.
This is a quote from the faceboo docs:
To convert sessions, send a POST
request to
https://graph.facebook.com/oauth/exchange_sessions
with a comma-separated list of
sessions you want to convert:
curl client_id=your_app_id \
-F client_secret=your_app_secret \
-F sessions=2.DbavCpzL6Yc_XGEI0Ip9GA__.3600.1271649600-12345,2.aBdC...
\
https://graph.facebook.com/oauth/exchange_sessions
The response from the request is a
JSON array of OAuth access tokens in
the same order as the sessions given:
[ {
"access_token": "...",
"expires": 1271649600, }, ... ]
However you don't need this method as its a bit more complex. For your use case i would suggest using a central point of authorization.
So you would specify your ONE domain as a redirect url. This domain is than SHARED between your websites. there you can obtain the fully valid access token and seamlessly redirect the user back to your specific project website and pass along the access token.
This way you can use the traditional easy authentication flow that is probably also more future proof.
The fact remains. Once the access token is generated you can perform any action from any domain, there is no difference as ther is literally no "domain" where the request is coming from (see above).
apart from that, if you want some nice javascript features to work - like the comments box or like button, you need to setup up open graph tags correctly.
if you have some implementation problems or as you said "domain errors" please describe them more clearly, include the steps you made and if possible an error message.