Microsoft Graph findMeetingTimes endpoint not working - microsoft-graph-api

Please do not report as duplicate because all other topics have not solved my issue, thanks.
I'm using Microsoft Graph api to list and create calendar events, however I can't seem to make the findMeetingTimes endpoint work.
This is my authorization URL:
https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?client_id=xxxxx&response_type=code&redirect_uri=xxxxx&response_mode=form_post&scope=openid%20profile%20User.ReadWrite%20User.ReadBasic.All%20Sites.ReadWrite.All%20Contacts.ReadWrite%20People.Read%20Notes.ReadWrite.All%20Tasks.ReadWrite%20Mail.ReadWrite%20Files.ReadWrite.All%20Calendars.ReadWrite&state=12345
Then I request an access token using the same scopes:
$request = json_decode($guzzle->post('https://login.microsoftonline.com/common/oauth2/v2.0/token', [
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded'
],
'form_params' => [
'client_id' => 'xxxxx',
'scope' => 'openid profile User.ReadWrite User.ReadBasic.All Sites.ReadWrite.All Contacts.ReadWrite People.Read Notes.ReadWrite.All Tasks.ReadWrite Mail.ReadWrite Files.ReadWrite.All Calendars.ReadWrite',
'code' => $auth_code,
'grant_type' => 'authorization_code',
'redirect_uri' => 'xxxxx',
'client_secret' => 'xxxxx'
],
])->getBody()->getContents());
After that I'm trying the findMeetingTimes endpoint using:
$request = json_decode($guzzle->post('https://graph.microsoft.com/v1.0/me/findMeetingTimes', [
'headers' => [
'Authorization' => 'Bearer ' . $accessToken,
'Content-Type' => 'application/json',
],
'body' => '{
"attendees": [
{
"type": "required",
"emailAddress": {
"name": "My Name",
"address": "myemail#hotmail.com"
}
}
],
"timeConstraint": {
"activityDomain":"work",
"timeslots": [
{
"start": {
"dateTime": "2019-04-02T09:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-04-03T17:00:00",
"timeZone": "Pacific Standard Time"
}
}
]
}
}',
])->getBody()->getContents());
However, it keeps returning:
401 - Unauthorized: Access is denied due to invalid credentials.
You do not have permission to view this directory or page using the credentials that you supplied.
Who's going to be my hero? :/

This is by design. From the documentation:
Note The findMeetingTimes action is currently available to Office 365 work or school mailboxes, but not personal, outlook.com mailboxes.

Related

Adding Calendar Event using Microsoft Graph API

I am trying to create an event in a calendar from a Powershell script. It needs to add the calendar event to the organizer's calendar and then to a list of attendees. Below is what I am sending in the body of the request.
{
"subject": "Let's go for lunch",
"IsOrganizer": "true",
"body": {
"contentType": "HTML",
"content": "Does noon work for you?"
},
"start": {
"dateTime": "2020-08-31T12:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2020-08-31T14:00:00",
"timeZone": "Pacific Standard Time"
},
"location":{
"displayName":"Harry's Bar"
},
"attendees": [
{
"emailAddress": {
"address":"attendee1#attendeeadress.com",
"name": "Attendee1"
},
"type": "required",
"status": {
"response": "none",
"time": "0001-01-01T00:00:00Z"
}
},
{
"emailAddress": {
"address":"attendee2#attendeeadress.com",
"name": "Attendee2"
},
"type": "required",
"status": {
"response": "none",
"time": "0001-01-01T00:00:00Z"
}
}
],
"organizer":{
"emailAddress":{
"name":"Specific Calendar",
"address":"calendarname#organizerorganization.onmicrosoft.com"
}
},
"allowNewTimeProposals": true
}
It appears successfully on the calendar of the attendees but not on the main organizer's calendar. Can anyone tell me what I am doing wrong and how I can get this to appear on the main organizer's calendar?
Thanks!
UPDATE - This is how I am getting the user token.
$Body = #{
'client_id' = 'my_client_id'
'scope' = 'https://graph.microsoft.com/.default'
'client_secret' = 'my_client_secret'
'grant_type' = 'password'
'userName' = 'calendarname#organizerorganization.onmicrosoft.com'
'password' = 'password'
}
It is now my understanding that this user should be set as the organizer of an event by default.
You can create an event using ROPC flow which gives you the user access token and using it you can call the /events endpoint with your payload as shown below.
POST https://graph.microsoft.com/v1.0/me/calendar/events
If you create an event with this token and give username as calendarname#organization.onmicrosoft.com this will be the organizer of the event.
And you can update 'subject', 'body/content' but you cannot update the event's 'start' and 'end' properties which is already a finished event.

Unable to view highcharts in my yii2 project

I have installed the highcharts package in my project. Now I am trying to view a sample chart but I am getting an error.
use miloschuman\highcharts\Highcharts;
<?=
Highcharts::widget([
'options' => [
'title' => ['text' => 'Fruit Consumption'],
'xAxis' => [
'categories' => ['Apples', 'Bananas', 'Oranges']
],
'yAxis' => [
'title' => ['text' => 'Fruit eaten']
],
'series' => [
['name' => 'Jane', 'data' => [1, 0, 4]],
['name' => 'John', 'data' => [5, 7, 3]]
]
]
]);
?>
Error
Invalid Argument – yii\base\InvalidArgumentException
The file or directory to be published does not exist: F:\xampp\htdocs\mdc/vendor\bower/highcharts
Update 1
Below is my stack trace
Update 2
Below is my composer.json
{
"name": "yiisoft/yii2-app-advanced",
"description": "Yii 2 Advanced Project Template",
"keywords": ["yii2", "framework", "advanced", "project template"],
"homepage": "http://www.yiiframework.com/",
"type": "project",
"license": "BSD-3-Clause",
"support": {
"issues": "https://github.com/yiisoft/yii2/issues?state=open",
"forum": "http://www.yiiframework.com/forum/",
"wiki": "http://www.yiiframework.com/wiki/",
"irc": "irc://irc.freenode.net/yii",
"source": "https://github.com/yiisoft/yii2"
},
"minimum-stability": "dev",
"require": {
"php": ">=5.4.0",
"yiisoft/yii2": "~2.0.13",
"yiisoft/yii2-bootstrap": "~2.0.0",
"yiisoft/yii2-swiftmailer": "~2.0.0",
"luoxiaojun1992/yii2-tinker": "*",
"kartik-v/yii2-grid": "#dev",
"kartik-v/yii2-widget-select2": "#dev",
"kartik-v/yii2-mpdf": "dev-master",
"moonlandsoft/yii2-phpexcel": "*",
"nirvana-msu/yii2-showloading": "1.0.*#dev",
"kartik-v/yii2-krajee-base": "^2.0",
"kartik-v/yii2-widget-spinner": "#dev",
"edwinhaq/yii2-simple-loading": "*",
"c006/yii2-submit-spinner": "*",
"kartik-v/yii2-detail-view": "*",
"fedemotta/yii2-cronjob": "*",
"kartik-v/yii2-widget-datetimepicker": "*",
"kartik-v/yii2-date-range": "dev-master",
"phpoffice/phpspreadsheet": "^1.2",
"linslin/yii2-curl": "*",
"kartik-v/yii2-widget-fileinput": "#dev",
"kartik-v/yii2-dialog": "*",
"google/apiclient": "^2.0",
"delight-im/str": "^2.4",
"mongosoft/yii2-soap-client": "dev-master",
"kartik-v/yii2-export": "#dev",
"ext-json": "*",
"miloschuman/yii2-highcharts-widget": "*",
"simialbi/yii2-widget-chart": "^1.0#dev",
"onmotion/yii2-widget-apexcharts": "dev-master",
"2amigos/yii2-chartjs-widget": "~2.0",
"kartik-v/yii2-bootstrap4-dropdown": "#dev",
"practically/yii2-chartjs": "dev-master",
"php-parallel-lint/php-console-color": "dev-master",
"nnnick/chartjs": "v2.9.3"
},
"require-dev": {
"yiisoft/yii2-debug": "~2.0.0",
"yiisoft/yii2-gii": "~2.0.0",
"yiisoft/yii2-faker": "~2.0.0",
"codeception/base": "^2.2.3",
"codeception/verify": "~0.3.1"
},
"config": {
"process-timeout": 1800,
"fxp-asset": {
"enabled": false
}
},
"extra": {
"asset-installer-paths": {
"npm-asset-library": "vendor/npm",
"bower-asset-library": "vendor/bower"
}
},
"scripts": {
"post-install-cmd": "php init --env=Development --overwrite=n"
},
"autoload": {
"psr-4": {
"kartik\\spinner\\": "",
"nirvana\\showloading\\": ""
}
},
"repositories": [{
"type": "composer",
"url": "https://asset-packagist.org"
}]
}
Update 3
Removed highcharts package from composer.json and then executed composer update
F:\xampp\htdocs\mdc>composer require --prefer-dist miloschuman/yii2-highcharts-widget "*"
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 2 installs, 0 updates, 0 removals
- Installing bower-asset/highcharts (v7.2.1): Loading from cache
- Installing miloschuman/yii2-highcharts-widget (dev-master 260b946): Loading from cache
Package codeception/base is abandoned, you should avoid using it. No replacement was suggested.
Package jakub-onderka/php-console-color is abandoned, you should avoid using it. Use php-parallel-lint/php-console-color instead.
Package jakub-onderka/php-console-highlighter is abandoned, you should avoid using it. Use php-parallel-lint/php-console-highlighter instead.
Writing lock file
Generating autoload files
14 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
Getting same error
Invalid Argument – yii\base\InvalidArgumentException
The file or directory to be published does not exist: F:\xampp\htdocs\mdc/vendor\bower/highcharts
Update 4
As per #Taron 1st solution I have backend/config/main.php
<?PHP
$params = array_merge(
require(__DIR__ . '/../../common/config/params.php'),
require(__DIR__ . '/../../common/config/params-local.php'),
require(__DIR__ . '/params.php'),
require(__DIR__ . '/params-local.php')
// require(__DIR__ .'/main-local.php')
);
return [
'id' => 'app-backend',
'basePath' => dirname(__DIR__),
'controllerNamespace' => 'backend\controllers',
'bootstrap' => ['log'],
'modules' => [
'gridview' => [
'class' => '\kartik\grid\Module'
],
'api' => [
'class' => 'backend\modules\api\Api',
],
],
'timeZone' => 'Asia/Karachi',
'components' => [
'request' => [
'csrfParam' => '_csrf-backend',
'parsers' => [
'application/json' => 'yii\web\JsonParser',
],
'enableCookieValidation' => false,
'enableCsrfValidation' => false,
],
'user' => [
'identityClass' => 'common\models\User',
'enableAutoLogin' => true,
'identityCookie' => ['name' => '_identity-backend', 'httpOnly' => true],
],
'session' => [
// this is the name of the session cookie used for login on the backend
'name' => 'advanced-backend',
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'errorHandler' => [
'errorAction' => 'site/error',
],
'urlManager' => [
'class' => 'yii\web\UrlManager',
'showScriptName' => false,
'enablePrettyUrl' => true,
'rules' => array(
'<controller:\w+>/<id:\d+>' => '<controller>/view',
'<controller:\w+>/<action:\w+>/<id:\d+>' => '<controller>/<action>',
'<controller:\w+>/<action:\w+>' => '<controller>/<action>',
),
],
],
'params' => $params,
];
How can I get rid of this error?
Any help would be highly appreciated
Looks like bower assets stored in path /vendor/bower-assets, but your script tries to load assets from vendor/bower (bower assets path error). Try solution bellow, I hope one of them will help you.
Solution first:
Just add aliases bellow to your config file/files (config/web.php)
'aliases' => [
'#bower' => '#vendor/bower-asset',
'#npm' => '#vendor/npm-asset',
],
Solution second:
Remove composer.lock file
Add package fxp: composer globalrequire "fxp/composer-asset-plugin:~1.1.1"
Reinstall composer: composer --prefer-dist install

Tokens returned by MSAL.JS contain none of the optional claims

The setup is as follows:
SPA web app that connects to a backend API. It's supposed to log in the user, request an access_token to the API and use it on all requests. Call it the Application.
Backend API that is supposed to receive access_tokens and authorise users based on the groups claim contained in it. Call it the API.
Configuration on the side of Azure AD:
The Application has redirect uris configured and is given an API permission to the API (the API.User scope).
The Backend exposes the API.User scope and authorises The Application as an Authorized client app.
Now, to get the groups claim I've added it to token configuration in both apps. Since it didn't work, I went and added some more optional claims to see if any of them are returned. They're not. The relevant parts of the manifest look like this:
"groupMembershipClaims": "All",
"oauth2AllowIdTokenImplicitFlow": true,
"oauth2AllowImplicitFlow": true,
"optionalClaims": {
"idToken": [
{
"name": "email",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "groups",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "nickname",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "given_name",
"source": null,
"essential": false,
"additionalProperties": []
}
],
"accessToken": [
{
"name": "email",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "groups",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "nickname",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "given_name",
"source": null,
"essential": false,
"additionalProperties": []
}
],
"saml2Token": [
{
"name": "groups",
"source": null,
"essential": false,
"additionalProperties": []
}
]
}
Both app registrations are configured the same (with respect to the above values).
The frontend code retrieving the token:
msalInstance = new Msal.UserAgentApplication(
{
auth: {
clientId: <the Application's client id>
}
}
);
this.msalInstance.handleRedirectCallback((error, response) => {
console.warn("In handleRedirectCallback");
console.warn(JSON.stringify(error));
console.warn(JSON.stringify(response));
});
if (this.msalInstance.getAccount()) {
const request = {
scopes: ['api://<the API client id>/API.User']
}
this.msalInstance.acquireTokenSilent(request)
.then(response => {
console.warn("In acquireTokenSilent then");
console.warn(JSON.stringify(response));
})
.catch(err => {
if (err.name === 'InteractionRequiredAuthError') {
return this.msalInstance.acquireTokenRedirect(request);
}
});
}
else {
const request = {
scopes: ['user.read', 'email', 'openid', 'profile']
};
this.msalInstance.loginRedirect(request);
}
I am clearly doing something wrong, as all access_tokens and id_tokens have the same layout completely independent of any changes I make to the app registrations or the request.scopes. I see that the MSAL request has a claimsRequest field, but it's undocumented and I don't know what should be put there. The MSDN docs make it sound as if all I needed to do was configure the app registration and the claims would be appended to the retrieved tokens, but it's clearly not the case.
Is there something else I have to configure to get the groups claim?
EDIT:
Example id_token layout that I'm getting:
{
"aud": "api://<the Application client id>",
"iss": "https://login.microsoftonline.com/<the Tenant id>/",
"iat": 1585052362,
"nbf": 1585052362,
"exp": 1585056262,
"aio": <Azure AD opaque string>,
"given_name": "<My first name>",
"hasgroups": "true",
"name": "<My account name>",
"nonce": <some guid>,
"oid": "<my account OID>",
"preferred_username": "<my email>",
"sub": <...>,
"tid": "<the tenant id>",
"uti": <Azure AD opaque string>,
"ver": "2.0"
}
example access_token I'm getting:
{
"aud": "api://<the Application client id>",
"iss": "https://sts.windows.net/<the Tenant id>/",
"iat": 1585052365,
"nbf": 1585052365,
"exp": 1585056265,
"acr": "1",
"aio": <Azure AD opaque string>,
"appid": "<the Application client id>",
"appidacr": "0",
"family_name": <my last name>,
"given_name": <my first name>,
"hasgroups": "true",
"ipaddr": <my ip addr>,
"name": <my account name>,
"oid": <my account oid>,
"onprem_sid": <not sure what this is, but some identifier>,
"scp": "API.User",
"sub": <...>,
"tid": <the tenant ID>,
"unique_name": <my email>,
"upn": <my email>,
"uti": <Azure AD opaque string>,
"ver": "1.0"
}
Since you commented that you are getting the hasgroups claim, it means the groups were not included in the token for most likely, size restrictions.
The claim is documented here: https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens.
Relevant quote from there:
If present, always true, denoting the user is in at least one group. Used in place of the groups claim for JWTs in implicit grant flows if the full groups claim would extend the URI fragment beyond the URL length limits (currently 6 or more groups)
So 5 is the maximum in implicit flow.
The 200 maximum is for e.g. authorization code flow.

Rails api is not returning access-token and client to external url via devise token auth

I'm having an issue with devise_token_auth returning a client and access-token back to my front end. It works fine in my test environment and I get the expected results. But in my dev environment I am using a external url. This is the response I get when I create a session:
Object {
"config": Object {
"adapter": [Function xhrAdapter],
"baseURL": "http://93ae6a5f.ngrok.io/api/v1",
"data": "{\"email\":\"test#gmail.com\",\"password\":\"password\"}",
"headers": Object {
"Accept": "application/json",
"Content-Type": "application/json",
},
"maxContentLength": -1,
"method": "post",
"timeout": 0,
"transformRequest": Object {
"0": [Function transformRequest],
},
"transformResponse": Object {
"0": [Function transformResponse],
},
"url": "http://93ae6a5f.ngrok.io/api/v1/auth/sign_in",
"validateStatus": [Function validateStatus],
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
},
"data": Object {
"data": Object {
"allow_password_change": false,
"email": "test#gmail.com",
"id": 1,
"image": null,
"name": null,
"nickname": null,
"provider": "email",
"uid": "test#gmail.com",
"username": null,
},
},
"duration": 731,
"headers": Object {
"cache-control": "public, max-age=0",
"content-type": "application/json; charset=utf-8",
"etag": "W/\"0fa41fc630ddb8ffc9b9f9f9b90849b5\"",
"transfer-encoding": "chunked",
"vary": "Origin",
"x-request-id": "320d3bd6-7e94-48b4-8e14-fe434d593b6a",
"x-runtime": "0.303548",
},
"ok": true,
"originalError": null,
"problem": null,
"status": 200,
}
I went through the devise_token_auth docs and have already added this to my application.rb
config.middleware.use Rack::Cors do
allow do
origins '*'
resource '*',
headers: :any,
expose: ['access-token', 'expiry', 'token-type', 'uid', 'client'],
methods: [:get, :post, :options, :delete, :put]
end
end
Anyone have any thoughts on how to get this working?
Did you add the following to your controller?
include DeviseTokenAuth::Concerns::SetUserByToken

Swagger UI - Try it Out! Returns whole Swagger Doc

When I ran following command :
rake swagger:docs
It returns me proper JSON files for each controllers.
When I access swagger-ui, it gives me proper page :
But when I click on Try it Out!, it returns me whole JSON like below :
I am new to Swagger. Can someone please help me out, where am I going wrong ?
UPDATE :
My public directory structure :
UPDATE
trucks.json :
{
"apiVersion": "v1",
"swaggerVersion": "1.2",
"basePath": "http://localhost:3000",
"resourcePath": "trucks",
"apis": [
{
"path": "/api/v1/trucks.json",
"operations": [
{
"summary": "Fetches all Trucks",
"parameters": [
{
"paramType": "header",
"name": "X-Auth-Token",
"type": "string",
"description": "Authentication Token",
"required": true
}
],
"responseMessages": [
{
"code": 401,
"responseModel": null,
"message": "Unauthorized"
},
{
"code": 406,
"responseModel": null,
"message": "The request you made is not acceptable"
}
],
"nickname": "API::V1::Trucks#index",
"method": "get"
}
]
}
],
"authorizations": null
}
Figured out the solution. Posting so that if anyone stumbles upon can try it out.
My swagger docs configuration looked like below :
Swagger::Docs::Config.register_apis({
'v1' =>{
:api_extension_type => :json,
:api_file_path => "public",
:base_path => 'http://localhost:3000',
:parent_controller => ApplicationController,
:base_api_controller => ActionController::Base,
:camelize_model_properties => false,
:clean_directory => true,
:attributes => {
:info => {
"title" => "Swagger Yattya",
"description" => "Yattya api documentation",
"termsOfServiceUrl" => "http://helloreverb.com/terms/",
"contact" => "apiteam#wordnik.com",
"license" => "Apache 2.0",
"licenseUrl" => "http://www.apache.org/licenses/LICENSE-2.0.html"
}
}
}
})
The first line wasn't required :
:api_extension_type => :json
Removed this line from configuration and worked like a charm!

Resources