{"id":7314,"date":"2023-08-04T16:00:50","date_gmt":"2023-08-04T15:00:50","guid":{"rendered":"https:\/\/rakhesh.com\/?p=7314"},"modified":"2023-08-04T18:49:21","modified_gmt":"2023-08-04T17:49:21","slug":"getoffice365groupsactivitydetail-and-s2sunauthorized-and-custom-connectors","status":"publish","type":"post","link":"https:\/\/rakhesh.com\/azure\/getoffice365groupsactivitydetail-and-s2sunauthorized-and-custom-connectors\/","title":{"rendered":"getOffice365GroupsActivityDetail and S2SUnauthorized and custom connectors"},"content":{"rendered":"
It always impresses and scares me when I am trying to figure something out and while Googling I come across one of my own blog posts. Impressive, coz “wow I was so smart a few months ago and had figured this out!” but scary coz “shit, I’ve forgotten I ever did this”. \ud83d\ude35\u200d\ud83d\udcab<\/p>\n
Case in hand, yesterday<\/a> I blogged out the HTTP with Azure AD connector. I had forgotten there was a blog post on it, and while I was looking to do some more stuff with it today I came across two more on my side.<\/p>\n Between these two posts, I think they capture everything I know (or should know) about this connector.<\/p>\n Anyways, a colleague wanted to use the HTTP with Azure AD connector to get reports. The account in question has the Reports Reader role, and he was trying the following URL: But it failed:<\/p>\n It’s not surprising it failed. The connector has a limited<\/a> set of scopes:<\/p>\n <\/p>\n That is to say, it probably doesn’t have the I could go the route of an HTTP connector, and I did spend some time fooling around with that, but eventually gave up. Using an HTTP connector has the draw back that I need to send the username and password as part of the password flow<\/a>. There are options to authenticate via OAuth 2.0 with the HTTP connector but I couldn’t quite figure out how to make it work with an App Registration I created that gives the delegated Anyways, using a custom connector is more fun. And reusable. Plus I can setup the connector for others in their environment, without handing over the secret to others. Way more nifty in my opinion.<\/p>\n So here’s what I did.<\/p>\n First, I created an App Registration. Just a standard one, but I added the delegated <\/p>\n Then I created a secret, and noted that.<\/p>\n Next, I went to Power Automate and created a custom connector.<\/p>\n Go to Data > Custom Connectors > New custom connector.<\/p>\n <\/p>\n Create from blank. Give it a name.<\/p>\n <\/p>\n And description. And change host to graph.microsoft.com.<\/p>\n <\/p>\n Then go to the next page, Security.<\/p>\n I want OAuth 2.0 and Azure AD.<\/p>\n <\/p>\n Fill in the rest of the details from the App Registration. I left the Tenant ID as common, but filled in the resource URL as <\/p>\n Click “Create Connector”.<\/p>\n <\/p>\n That should generate a Redirect URI.<\/p>\n <\/p>\n I added that to the App Registration.<\/p>\n <\/p>\n Go to the next section, Definition.<\/p>\n Add an action.<\/p>\n <\/p>\n Update<\/strong>: Later, I changed the above to be like this:<\/p>\n <\/p>\n That’s because I realized there’s no way to take an input of the number of days, so I might as well create separate ones.<\/em><\/p>\n And a request, for that action.<\/p>\n <\/p>\n The URL is Update<\/strong>: Later, I changed the URL to be Click on Response, add a default response,\u00a0 and I added the following:<\/p>\n I got this from the API documentation<\/a>.<\/p>\n <\/p>\n This one’s a bit odd in that the response is the headers.<\/p>\n And that’s it, save\/ update the connector.<\/p>\n Now in my Power Automate, I can call this custom connector.<\/p>\n <\/p>\n After selecting I can see the action I created.<\/p>\n <\/p>\n Save, and test\/ run it.<\/p>\n On the face of it, it throws an error.<\/p>\n <\/p>\n But that’s misleading, because the headers show the content I want:<\/p>\n <\/p>\n So I create a Compose action after this connector, and use the Location as input.<\/p>\n <\/p>\n And set it to run even after the connector has failed.<\/p>\n <\/p>\n Run it now, and the flow succeeds. \ud83d\ude42<\/p>\n <\/p>\n I downloaded the JSON and added more actions to it.<\/p>\n These are all the valid “period” options for that call. I wish there was some way to take an input for GET operations. There is, if I switch to POST, but that’s not what I need.<\/p>\n Update<\/strong>: Later in the day, when Googling on something else, I came across this blog post<\/a> from Microsoft. It’s a good one. And worth noting this point:<\/p>\n Custom connectors are supported by Microsoft Azure API Management infrastructure. When a connection to the underlying API is created, the API Management gateway stores the API credentials or tokens, depending on the type of authentication used, on a per-connection basis in a token store. This solution enables authentication at the connection level.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":" It always impresses and scares me when I am trying to figure something out and while Googling I come across one of my own blog posts. Impressive, coz “wow I was so smart a few months ago and had figured this out!” but scary coz “shit, I’ve forgotten I ever did this”. \ud83d\ude35\u200d\ud83d\udcab Case in … Continue reading getOffice365GroupsActivityDetail and S2SUnauthorized and custom connectors<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[887],"tags":[182,982,1065,1046,1037],"jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/posts\/7314"}],"collection":[{"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/comments?post=7314"}],"version-history":[{"count":3,"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/posts\/7314\/revisions"}],"predecessor-version":[{"id":7342,"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/posts\/7314\/revisions\/7342"}],"wp:attachment":[{"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/media?parent=7314"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/categories?post=7314"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rakhesh.com\/wp-json\/wp\/v2\/tags?post=7314"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}\n
https:\/\/graph.microsoft.com\/v1.0\/reports\/getOffice365GroupsActivityDetail(period='D90')<\/code><\/p>\n
{\r\n \"error\": {\r\n \"code\": \"UnknownError\",\r\n \"message\": \"{\\\"error\\\":{\\\"code\\\":\\\"S2SUnauthorized\\\",\\\"message\\\":\\\"Invalid permission.\\\"}}\",\r\n \"innerError\": {\r\n \"date\": \"2023-08-04T09:25:01\",\r\n \"request-id\": \"364325b0-65aa-4034-ae12-53f1ac1c4ce3\",\r\n \"client-request-id\": \"364325b0-65aa-4034-ae12-53f1ac1c4ce3\"\r\n }\r\n }\r\n}<\/pre>\n
Reports.Read.All<\/code> delegated permission assigned to it, so even though the account can do it the connector can’t. Bummer.<\/p>\n
Reports.Read.All<\/code> permissions. Could be that I was just being thick when figuring it out.<\/p>\n
Reports.Read.All<\/code> permission to it and did an admin consent.<\/p>\n
https:\/\/graph.microsoft.com<\/code> (fill that exactly; I know this experience<\/a>).<\/p>\n
https:\/\/graph.microsoft.com\/v1.0\/reports\/getOffice365GroupsActivityDetail<\/code><\/p>\n
https:\/\/graph.microsoft.com\/v1.0\/reports\/getOffice365GroupsActivityDetail(period='D90')<\/code> to match the updated name above<\/p>\n
Content-Type: text\/plain\r\nLocation: https:\/\/reports.office.com\/data\/download\/JDFKdf2_eJXKS034dbc7e0t__XDe<\/pre>\n
{\r\n \"swagger\": \"2.0\",\r\n \"info\": {\r\n \"title\": \"Graph API - Reports\",\r\n \"description\": \"Gets reports from Graph API\",\r\n \"version\": \"1.0\"\r\n },\r\n \"host\": \"graph.microsoft.com\",\r\n \"basePath\": \"\/\",\r\n \"schemes\": [\r\n \"https\"\r\n ],\r\n \"consumes\": [],\r\n \"produces\": [],\r\n \"paths\": {\r\n \"\/v1.0\/reports\/getOffice365GroupsActivityDetail(period='D7')\": {\r\n \"get\": {\r\n \"responses\": {\r\n \"default\": {\r\n \"description\": \"default\",\r\n \"schema\": {\r\n \"type\": \"string\"\r\n },\r\n \"headers\": {\r\n \"Content-Type\": {\r\n \"description\": \"Content-Type\",\r\n \"type\": \"string\"\r\n },\r\n \"Location\": {\r\n \"description\": \"Location\",\r\n \"type\": \"string\"\r\n }\r\n }\r\n }\r\n },\r\n \"summary\": \"Get O365 Groups Activity Details - 7 days\",\r\n \"description\": \"Get O365 Groups Activity Details - 7 days\",\r\n \"operationId\": \"GetOffice365GroupsActivityDetail7\",\r\n \"parameters\": []\r\n }\r\n },\r\n \"\/v1.0\/reports\/getOffice365GroupsActivityDetail(period='D30')\": {\r\n \"get\": {\r\n \"responses\": {\r\n \"default\": {\r\n \"description\": \"default\",\r\n \"schema\": {\r\n \"type\": \"string\"\r\n },\r\n \"headers\": {\r\n \"Content-Type\": {\r\n \"description\": \"Content-Type\",\r\n \"type\": \"string\"\r\n },\r\n \"Location\": {\r\n \"description\": \"Location\",\r\n \"type\": \"string\"\r\n }\r\n }\r\n }\r\n },\r\n \"summary\": \"Get O365 Groups Activity Details - 30 days\",\r\n \"description\": \"Get O365 Groups Activity Details - 30 days\",\r\n \"operationId\": \"GetOffice365GroupsActivityDetail30\",\r\n \"parameters\": []\r\n }\r\n },\r\n \"\/v1.0\/reports\/getOffice365GroupsActivityDetail(period='D90')\": {\r\n \"get\": {\r\n \"responses\": {\r\n \"default\": {\r\n \"description\": \"default\",\r\n \"schema\": {},\r\n \"headers\": {\r\n \"Content-Type\": {\r\n \"description\": \"Content-Type\",\r\n \"type\": \"string\"\r\n },\r\n \"Location\": {\r\n \"description\": \"Location\",\r\n \"type\": \"string\"\r\n }\r\n }\r\n }\r\n },\r\n \"summary\": \"Get O365 Groups Activity Details - 90 days\",\r\n \"description\": \"Get O365 Groups Activity Details - 90 days\",\r\n \"operationId\": \"GetOffice365GroupsActivityDetail90\",\r\n \"parameters\": []\r\n }\r\n },\r\n \"\/v1.0\/reports\/getOffice365GroupsActivityDetail(period='D180')\": {\r\n \"get\": {\r\n \"responses\": {\r\n \"default\": {\r\n \"description\": \"default\",\r\n \"schema\": {\r\n \"type\": \"string\"\r\n },\r\n \"headers\": {\r\n \"Content-Type\": {\r\n \"description\": \"Content-Type\",\r\n \"type\": \"string\"\r\n },\r\n \"Location\": {\r\n \"description\": \"Location\",\r\n \"type\": \"string\"\r\n }\r\n }\r\n }\r\n },\r\n \"summary\": \"Get O365 Groups Activity Details - 180 days\",\r\n \"description\": \"Get O365 Groups Activity Details - 180 days\",\r\n \"operationId\": \"GetOffice365GroupsActivityDetail180\",\r\n \"parameters\": []\r\n }\r\n }\r\n },\r\n \"definitions\": {},\r\n \"parameters\": {},\r\n \"responses\": {},\r\n \"securityDefinitions\": {\r\n \"oauth2-auth\": {\r\n \"type\": \"oauth2\",\r\n \"flow\": \"accessCode\",\r\n \"authorizationUrl\": \"https:\/\/login.microsoftonline.com\/common\/oauth2\/authorize\",\r\n \"tokenUrl\": \"https:\/\/login.windows.net\/common\/oauth2\/authorize\",\r\n \"scopes\": {\r\n \"Reports.Read.All\": \"Reports.Read.All\"\r\n }\r\n }\r\n },\r\n \"security\": [\r\n {\r\n \"oauth2-auth\": [\r\n \"Reports.Read.All\"\r\n ]\r\n }\r\n ],\r\n \"tags\": []\r\n}<\/pre>\n