ms Graph api, calendarView 403-accessdenied error - azure-ad-graph-api

First, I'm using Spring, Jetty, Retrofit.
When I use calendarView in local, they return the successful values successfully.
But, When others connect to my local server and call this api, it always returns me 403-AccessDenied error.
(additionally, When they call another ms api, they return the successful values.)
I think I have set all the recommended permissions in Graph api.
But this could be my illusion.
In order for someone else to call api from my local server, what should I do?
Or Am I missing anything on this matter?
These are my permissions.
"openid",
"offline_access",
"profile",
"User.ReadWrite",
"Mail.ReadWrite",
"Calendars.ReadWrite",
"User.ReadBasic.All",
"BookingsAppointment.ReadWrite.All"
This is my azure info.
And I'm using this calendar view api
https://learn.microsoft.com/en-us/graph/api/calendar-list-calendarview?view=graph-rest-1.0&tabs=http
And Using This URL in my code(in this case, I'm using batch request)
GET | "/users/"+getAddress()+"/calendarView?startDateTime="+getStartTime()+"&endDateTime="+getEndTime()

Based on your description, other users are trying to access the calendarView of the user "{Room}".
In this case, you need 2 more configurations.
User "{Room}" gives mailbox permissions "Full Access" to other users
in Office 365. See Use the EAC to assign permissions to individual
mailboxes. (you should be able to find the room under
Resources. And the process can take up to hours for the changes to propagate through the system and be in effect.)
Add one more delegated permission: Calendars.ReadWrite.Shared into
the app registed in Azure AD.

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.

Create MS Teams chats with MS Graph (or 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.

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.

How to list Azure VMs using the REST API with Oauth2?

The Problem
MS Azure provides an extensive REST API. However, there is a significant amount of complexity when trying to get that API to work. From outdated and incomplete documentation to simple examples not working, performing what should be an easy task is instead nightmarish.
The Task
What are the exact, precise, detailed steps necessary to list the available VMs for someone who has logged in using Oauth2? For instance, this can be done using the azure-cli.
azure vm list
What are the steps to accomplish the same thing using REST and Oauth2?
The Requirements
The answer must not use Visual Studio, PowerShell, C#, an SDK, or any other such tool to accomplish this task. Only the portal is allowed for setup, and only Oauth2 is allowed for authorization, and only the REST API is allowed for actual information retrieval.
The answer must not simply link to external sources, although external references are encouraged for completeness.
The answer may assume the user has an Azure account. It must include information about creating the Oauth2 client, credentials, and any step necessary to get the appropriate token.
The answer must be detailed.
The answer must provide examples. Images, too are strongly encouraged.
The answer should include information about possible errors, their meanings, and what too look for to fix them.
First, we can find this rest API in azure resource portal. It is the same with Azure CLI command azure vm list.
I have tested it on my local with http request. here is my tested screenshot:
Request URL: https://management.azure.com/subscriptions/<subscription ID>/providers/Microsoft.Compute/virtualMachines?api-version=2016-03-30
Header:Authorization: bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI.....
So It is very import if we get the access token. The following demonstrate us how to get the access token.
Get Token(POST):
Request URL: https://login.microsoftonline.com/<tenant id>/oauth2/token
Body: grant_type=client_credentials&client_id=<client id>&resource=https%3A%2F%2Fmanagement.core.windows.net%2F&client_secret=<client secret>
Here is my screenshot in fildder:
We need to get client id and client secret in azure ad application. For how to regist an application in Azure AD. Please have a look at this article: https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal.
Please note:
1) we need to add "Windows Azure Service Management API" in portal "Required permissions" like the following screenshot:
2) We need assign "Contributor" for this service principal. click subscription-> Access Control-> click Add -> click "Select a Role" -> click Contributor->click Add User-> Find the application you created above-> click OK.
Overview
Making requests against the Azure Rest API is a bit more complicated than perhaps you would think at first glance. In particular, there are a number of esoteric and not-so-helpful error messages you may run into while getting the nobs tweaked just right.
Introduction and Terms
Setting up The Application
Getting the access_token
Making the API request
Common errors thus far
Introduction and Terms
One of the pieces of this process that can make it so confusing and difficult is the terminology. Until you understand that, knowing how to deal with errors is very difficult. We'll go over some of the more common ones here.
Subscription - This is basically what you'd expect. It refers to the Microsoft Azure Services subscription. It basically acts as the top-level umbrella for the organization.
Tenant - This is like a sub-organization, maybe a department or group. There can be multiple tenants under a single subscription.
User - As expected, a user is a single individual. Users are scoped to tenants.
Application - The Application is the software program trying to use the API. It must be registered and configured to do so.
Service Principal - This is essentially The Application. It is the entity making API Service requests.
Setting Up the Application
Although you might not guess it, this is probably the most complicated part of the process. Let's start by creating The Application in the portal.
Create The Application
Follow this click path: Azure Active Directory -> App Registrations -> New
There should be a form for application creation, with the following fields:
Name
This is simple the name of The Application. When authenticating, it will be shown to users. For the purposes of this "tutorial", we'll call it API Tutorial. This can be edited after creation.
Application Type
The type of The Application. For our purposes, we should choose "Web app/API". This cannot be edited after creation.
Sign-on URL
The is the redirect that will be used if we go the "authorization_code" route for sign on. This can be useful as the response will include an "id_token". We'll get into that a bit later. For now, let's make this http://123AzureApiTutorial.com/code. This can be edited after creation.
Once the Application has been created, you should see a property, Application ID. This is the client_id used in the OAuth2 flow. Take a note of its value.
Create the Client Secret
The OAuth2 flow requires a client secret value for authentication.
To generate it, follow this click path: Azure Active Directory -> App Registrations -> API Tutorial -> All Settings -> Keys
Enter the key description: API Tutorial Key, and the Duration: In 1 year.
Click Save. This will generate the Key Value. You must copy the value here and save it somewhere. You will not have another opportunity to do so.
This value is the client_secret in the OAuth2 flow.
Add the correct permissions
To get to the permissions, follow this click path: Azure Active Directory -> App Registrations -> API Tutorial -> All Settings -> Required Permissions -> Add
Here you will see the list of possible APIs. The one we care about for Azure is Windows Azure Service Management API. There is currently only one permission: Access Azure Service Management as organization users (preview). Select it, click Select, and then Done.
Getting the access_token
The access_token is what allows us to make requests against the API. There are two primary ways to do this. I suggest reading about both before trying to implement them.
Authorization Code
The authorization code is a two-step process. First we obtain the authorization code, and then we use that to get the access_token. A benefit of this route is that we get back an id_token as well, with a variety of useful claims like the user's name, email address, etc.
The request format is as follows: (GET) https://login.microsoftonline.com/<tenant-id>/oauth2/authorize?client_id=<client-id>&scope=api&redirect_uri=<redirect-uri>&response_type=code&prompt=consent. Let's go over the parameters here really quick.
Tenant ID
This can be obtained be using the click path Azure Active Directory -> Properties and copy the Directory ID. This is, in fact the Tenant ID value. It just has a different name to help with the overall confusion.
Client ID
This is the Application ID we retrieved previously.
Scope
This is the scope of the code. We just want to use the API.
Redirect URI
This is the sign-on URL you specified when creating API Tutorial. After the user logs in, they will be redirected to this URL with a "code" parameter in the query string.
Response Type
This is what we want the response to be. We want an authorization code, so we just use the value code.
Prompt
This specifies whether or not to prompt the user to consent to the permissions. If we did not have this, and changed permissions, the request would just unexpectedly fail. Very frustrating. But it can be removed once permission has been granted as long as you don't change the permissions. If the application is accessing an API that requires admin permission, this value should be admin_consent.
Alright, so once we shoot off this request we will be redirected to the login page. We login, accept the permissions, and then we should be redirected to here: http://123AzureApiTutorial.com/code?code=SOME_REALLY_LONG_STRING_OF_CHARACTERS. That string of characters is the code.
Getting the Access Token
Next, we take the code and use it to get the access_token. To do so, we need to make another request.
(POST) https://login.microsoftonline.com/<tenant-id>/oauth2/token
In addition to the url, we need to add parameters. These should be consistent with the content type application/x-www-form-urlencoded. This means they are submitted as form parameters. They are as follows:
client_id
This is again the client id (Application ID) we already have.
client_secret
This is the Application Key we generated earlier. I hope you saved it! If not, go back to that step and generate another one.
code
This is the value of the code we just received: SOME_REALLY_LONG_STRING_OF_CHARACTERS.
`grant_type
Because we're going the authorization code route, this value should be authorization_code
redirect_uri
This is the redirect uri we specified for the API Tutorial. The value from our example should be http://123AzureApiTutorial.com/code.
resource
This is very important. It is the resource API we want to access. For the Azure API, this value is https://management.azure.com.
Our response will be a json object with a variety of fields. Of these, the one we care about is access_token. Yay!
Client Credentials
This methodology skips getting the code (and thus needing the redirect_uri) at the expense of not getting an id_token.
The request is the same as in the Getting the Access Token section, with a few small differences.
We do not need to specify redirect_uri.
The value of grant_type should change to client_credentials.
Alright, we have an access_token! Now we're cooking!
Making the API request
With all the prep work thus far, this is the easiest part of the process.
The API URL we are requesting against is:
https://management.azure.com/subscriptions/<subscription-id>/providers/Microsoft.Compute/virtualMachines?api-version=2016-03-30
Add the following header to the request:
Authorization: Bearer <access-token>. Yes, the access_token value must be prefaced with the word "Bearer" in the header value.
"But wait!" You exclaim. "How do I get the subscription id?"
Excellent question! To find it through the portal, click Subscriptions -> -> Overview and copy the Subscription Id value.
Use that value, and run the request. You should see all the vms listed!
Common errors thus far
InvalidAuthenticationToken
When making the API request, you get an error response that says something like this: InvalidAuthenticationToken: The access token is invalid. This means you haven't added the API permissions to the API Tutorial. Go back to the Add the correct permissions step and double-check you have the right permissions. Also, when requesting the token make sure you use the prompt=consent, otherwise the you will not be prompted with the new permissions and the token will fail.
InvalidAuthenticationTokenTenant
Make sure that the tenant-id used when requesting the token belongs to the subscriber used when making the API call.

Azure AD - Manage Group & User Assignments

I am an Azure Global Tenant Admin for our [Premium] Azure AD instance. I have a Web App that requires Group/User Assignment to access. We need to know which Groups and Users have been assigned access. The Azure UI does not let you query this information so I am wondering if there is any way to obtain a list of Groups/Users that have been assigned access to a Web App.
Edit: It looks like the Graph API version 1.5 now supports this. I can download the servicePrincipal ODATA with this URL:
GET string.Format("https://graph.windows.net/{0}/servicePrincipals?api-version=1.5&$filter=appId+eq+'{1}'",
tenant, clientId)
According to this MSDN post, I should be able to use a URL format like
GET string.Format("https://graph.windows.net/{0}/servicePrincipals/{1}/appRoleAssignedTo?api-version=1.5",
tenant, clientId)
However, I am receiving this error:
"Resource 'f4126638-cb47-48df-ad9d-57c0684b6575' does not exist or one of its queried reference-property objects are not present."}
In the second Graph call, I should be using the servicePrincipal's ObjectID returned from the first call instead of the Application's ClientID.