Graph API not allowing online meetings - microsoft-graph-api

I am currently setting up a web page where users can send event requests to others using the Microsoft Graph api. I would like users to be able to send an online meeting request and then provide the options of ms teams and Skype.
However as soon as I add the property 'isOnlineMeeting' and/or 'onlineMeetingProvider' I will always return an error 400 with a bad request. This is because the property doesn't exist on the /me/events.
(the response)
I have no idea why however, currently I am using the microsoft graph explorer to test the request.
I have made sure that every permission is needed to send an invite:
Calendar.Read
Calendar.Read.Shared
Calendar.ReadWrite
Calendar.ReadWrite.Shared
If a meeting is sent without these properties it works fine. I have created other personal outlook accounts and it works as expected with this property. I have asked other people in my org to try too and theirs works fine.
Does this mean that my ms account is broken in some way? if so how could I fix it in order to send this request.

Try this:
var body= "{email body};
var string = "{\"subject\": \"Join the Teams Meeting\", \"body\": {\"contentType\": \"HTML\", \"content\": \"" + body + "\" }, \"start\": {\"dateTime\": \"2020-09-28T19:30:34\",\"timeZone\": \"Pacific Standard Time\" }, \"end\": { \"dateTime\": \"2020-09-28T20:00:34\", \"timeZone\": \"Pacific Standard Time\"}, \"location\":{ \"displayName\":\"Team meeting\" }, \"attendees\": [ { \"emailAddress\": { \"address\":\"xxxx#in.xxx.com\", \"name\": \"xxxx xxxx\" }, \"type\": \"required\" } ],\"allowNewTimeProposals\": \"true\"}";
client = new RestClient("https://graph.microsoft.com/v1.0/me/events");
request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/json");
request.AddHeader("authorization", "Bearer " + token);
request.AddHeader("accept-language", "en");
request.AddHeader("accept", "application/json");
request.AddParameter("application/json", string, ParameterType.RequestBody);
response = client.Execute(request);
To generate token:
var client = new RestClient("https://login.microsoftonline.com/{tenant-Id}/oauth2/v2.0/token");
var request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("grant_type", "password");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=password&client_id={client-Id}&client_secret={client-secret}&scope={scopeurl}&userName={username}&password={password}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
var json = response.Content;
var JSONObject = JObject.Parse(json);
var token = (string)JSONObject["access_token"];

Related

How to implement OAuth2.0 using client credentials grant-type in a way that it supports Json raw body with token request in c#

My project is a web api project which is using owin for generating token after authentication. it is built using asp.net framework.
It currently accepts token request in below format -
var client = new RestClient("http://localhost:63202/1.0/token");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("grant_type", "client_credentials");
request.AddParameter("client_id", "12345667");
request.AddParameter("client_secret", "secret");
I want my API to support Json raw body instead of URL encoded one with the token request as below -
var client = new RestClient("http://localhost:63202/1.0/token");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/json");
var body = #"{" + "\n" +
#" "grant_type": "client_credentials"," + "\n" +#" "client_id": "1234567890""," + "\n" +#"client_secret": "channelsintegration123456789012345" + "\n" +
#"}"
request.AddParameter("application/json", body, ParameterType.RequestBody);
Issue - When the request is made and ValidateClientAuthentication() method is hit, the context doesn't have client id and client secret when I make the above (#2) request.

Is there any way to bulk delete all permissions of a file using the IGraphServiceClient?

As part of a user action, we are using the MS Graph Java SDK to first list all permissions of a file, then iterating over the list of permissions to delete each one individually. This seems to have some performance issues. We were wondering if there is any way to batch the calls using the IGraphServiceClient.
Relevant APIs used:
https://learn.microsoft.com/en-us/graph/api/driveitem-list-permissions?view=graph-rest-1.0&tabs=http
https://learn.microsoft.com/en-us/graph/api/permission-delete?view=graph-rest-1.0&tabs=http
You can make batch requests.
1. Create MSBatch Request Steps (examples below)
Request requestGetMe = new Request.Builder().url("https://graph.microsoft.com/v1.0/me/").build();
List<String> arrayOfDependsOnIdsGetMe = null;
MSBatchRequestStep stepGetMe = new MSBatchRequestStep("1", requestGetMe, arrayOfDependsOnIdsGetMe);
Request requestGetMePlannerTasks = new Request.Builder().url("https://graph.microsoft.com/v1.0/me/planner/tasks").build();
List<String> arrayOfDependsOnIdsGetMePlannerTasks = Arrays.asList("1");
MSBatchRequestStep stepMePlannerTasks = new MSBatchRequestStep("2", requestGetMePlannerTasks, arrayOfDependsOnIdsGetMePlannerTasks);
String body = "{" +
"\"displayName\": \"My Notebook\"" +
"}";
RequestBody postBody = RequestBody.create(MediaType.parse("application/json"), body);
Request requestCreateNotebook = new Request
.Builder()
.addHeader("Content-Type", "application/json")
.url("https://graph.microsoft.com/v1.0/me/onenote/notebooks")
.post(postBody)
.build();
MSBatchRequestStep stepCreateNotebook = new MSBatchRequestStep("3", requestCreateNotebook, Arrays.asList("2"));
2. Create MSBatch Request Content and get content
List<MSBatchRequestStep> steps = Arrays.asList(stepGetMe, stepMePlannerTasks, stepCreateNotebook);
MSBatchRequestContent requestContent = new MSBatchRequestContent(steps);
String content = requestContent.getBatchRequestContent();
3. Make call to $batch endpoint
OkHttpClient client = HttpClients.createDefault(auth);
Request batchRequest = new Request
.Builder()
.url("https://graph.microsoft.com/v1.0/$batch")
.post(RequestBody.create(MediaType.parse("application/json"), content))
.build();
Response batchResponse = client.newCall(batchRequest).execute();
4. Create MSBatch Response Content
MSBatchResponseContent responseContent = new MSBatchResponseContent(batchResponse);
Response responseGetMe = responseContent.getResponseById("1");
// Use the response of each request

DocuSign "invalid_grant" on posting jwtToken

I'm trying to achieve "Service Integration Authentication" following the steps here docusign docs and it's doing fine until Requesting the Access Token, where you send the jwt token (which is well formed)
I'm always getting "invalid_grant", and according to that doc, is because some of the claims are invalid. Is there another cause for that error?
All the claims looks good
C#:
//request access token
var client3 = new RestClient("https://" + _host);
var request3 = new RestRequest("/oauth/token", Method.POST);
request3.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request3.AddParameter("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer");
var headers = new[]
{
new Claim("alg", "RS256"),
new Claim("typ", "JWT"),
}.ToList();
var claims = new[] {
new Claim("iss", _integrationKey), //<-- integration key
new Claim("sub", OAuthGrant.Sub), //<-- returned from /oauth/userinfo (OK)
new Claim("iat", ToUnixTime(DateTime.Now).ToString(), ClaimValueTypes.Integer64),
new Claim("exp", ToUnixTime(DateTime.Now.AddHours(1)).ToString(), ClaimValueTypes.Integer64),
new Claim("aud", _host), //<-- "account-d.docusign.com"
new Claim("scope", "signature"),
}.ToList();
//build jwt from private key. token decodes just fine from https://jwt.io/
var jwtToken = CreateToken(claims, headers, "private-key.pem", Server.MapPath("/"));
request3.AddParameter("assertion", jwtToken);
System.Diagnostics.Debug.WriteLine("jwtToken:" + jwtToken);
var response = client3.Execute<OAuthToken>(request3);
System.Diagnostics.Debug.WriteLine("response content:" + response.Content); //<-- getting "invalid_grant"
return response.Data;
The jwt token was validated using https://jwt.io/ and decodes just fine.
Is docusign demo sandbox
Thanks in advance
daniel
My assumption is the library which you are using is generating wrong assertion for you. You can check DS SDK as well - ConfigureJwtAuthorizationFlow method in DS SDK, it will help you in generating the Assertion in correct way as expected by DS APIs.

Search for Twitter handles using Google Apps Script and Twitter API - doesn't work

I'm trying to find Twitter handles from a spreadsheet containing names of people.
I can't get it work with this request, which I believe is the one I should be using as I only have peoples names (e.g. Adam Smith): api.twitter.com/1.1/users/search.json?q=
I get the following error:
Request failed for api.twitter.com/1.1/users/search.json?q=Name returned code 403. Truncated server response: {"errors":[{"message":"Your credentials do not allow access to this resource","code":220}]} (use muteHttpExceptions option to examine full response) (line 38).'
I've tried searching this error but that hasn't helped me so far.
If I use, for example, this request, it works: api.twitter.com/1.1/users/show.json?screen_name=
So I can get the screen_name back in the spreadsheet, but that's pointless obviously because it needs the screen name to work in the first place...
The whole thing is based on this work, all the requests in that code work for me. It's just this search request that doesn't work. What's going wrong?
var CONSUMER_KEY = 'x';
var CONSUMER_SECRET = 'x';
function getTwitterHandles(name) {
// Encode consumer key and secret
var tokenUrl = "https://api.twitter.com/oauth2/token";
var tokenCredential = Utilities.base64EncodeWebSafe(
CONSUMER_KEY + ":" + CONSUMER_SECRET);
// Obtain a bearer token with HTTP POST request
var tokenOptions = {
headers : {
Authorization: "Basic " + tokenCredential,
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
},
method: "post",
payload: "grant_type=client_credentials"
};
var responseToken = UrlFetchApp.fetch(tokenUrl, tokenOptions);
var parsedToken = JSON.parse(responseToken);
var token = parsedToken.access_token;
// Authenticate Twitter API requests with the bearer token
var apiUrl = 'https://api.twitter.com/1.1/users/search.json?q=screen_name='+name;
var apiOptions = {
headers : {
Authorization: 'Bearer ' + token
},
"method" : "get"
};
var responseApi = UrlFetchApp.fetch(apiUrl, apiOptions);
var result = "";
if (responseApi.getResponseCode() == 200) {
// Parse the JSON encoded Twitter API response
var tweets = JSON.parse(responseApi.getContentText());
return tweets.id
}
Logger.log(result);
}
Edit: deleted the https a few times because of the URL limit
You can not search for users using application-only authentication (bearer token). See https://dev.twitter.com/oauth/application-only. A user context (access token) is needed for that request. You can get your own access token from https://apps.twitter.com.

IdentityServer3 Response status code does not indicate success: 400 (Bad Request)

I always get Bad Request 400 from IdentityServer3. I am trying for 3 days now but no luck :( Anyone could please tell me what am I doing wrong?
I am trying to access IdentityServer3 hosted by another vendor that I have no control. The vendor has asked us to implement Implement OAuth2 authentication with Bearer token. The vendor provided us with the Client ID, Client Secret and the URL to be used is http://www.xxxxxx.com/identity/connect/token
The vendor told us to use to request bearer token and use it in the request headers Authorization: Bearer
I can successfully obtain the bearer token from vendor. But when I call the
GET /api/profiles/myemailaddress#gmail.com I get Bad Request 400
Here is what I have done:
TokenClient client = new TokenClient("http://www.xxxxxx.com/identity/connect/token", "myclientid", "myclientsecret", AuthenticationStyle.PostValues);
var response = await client.RequestResourceOwnerPasswordAsync("myemailaddress#gmail.com", "mypassword", "profile"); // successfully gives me the token
i got the access token, now i want to use the token to request user profile:
var clienthttp = new HttpClient();
clienthttp.BaseAddress = new Uri("http://www.xxxxxx.com");
clienthttp.SetBearerToken(response.AccessToken);
var json = await clienthttp.GetStringAsync("http://www.xxxxxx.com/api/profiles/myemailaddress#gmail.com"); // error Bad Request 400
Additional Info:
"scopes_supported":["profile","offline_access"],
"claims_supported":[]
Thank you.
The vendor was expecting additional value in the header. Since my request was missing that additional value, they returned Bad Request. I had to modify my code to find the exact reason of bad request.
Here is the updated code, might be useful for someone:
var client = new HttpClient();
client.BaseAddress = new Uri("http://www.xxxxx.com");
client.SetBearerToken(response.AccessToken);
var callApiResponse = client.GetAsync("api/profiles/myemailaddress#gmail.com").Result;
string tokenresponse = callApiResponse.StatusCode.ToString();
string clientresult = callApiResponse.Content.ReadAsStringAsync().Result;
tokenresponse: "Bad Request 400"
clientresult: "Missing CompanyID in the header"
Then I knew that they also expect companyid in the header so I added it. then all was good.
client.DefaultRequestHeaders.Add("CompID", "xxxxxx");
I had a similar error (Response status code does not indicate success: 400 (Bad Request)) for different resource not identity server. i manage to resolve that using FormUrlEncodedContent
Refer below code
using (HttpClient client = new HttpClient())
{
string baseUrl = "https://*******.com/****"
Dictionary<string, string> jsonValues = new Dictionary<string, string>();
jsonValues.Add("username", "******");
jsonValues.Add("password", "******");
var contenta = new FormUrlEncodedContent(jsonValues);
var response = await client.PostAsync(baseUrl, contenta);
using (HttpContent content = response.Content)
{
string data = await content.ReadAsStringAsync();
if (data != null)
{
Console.WriteLine(data);
}
}
}

Resources