MS graph API: 400 AuthenticationError with "/me/onlineMeetings" request - javascript

I am trying to create an online meeting and recover its URL like explained here in the docs, but when the request is run I get this error:
{
"statusCode": 400,
"code": "AuthenticationError",
"message": "Error authenticating with resource",
"requestId": "652ea3be-6a97-47e8-bfc6-3d7d1d51d425",
"date": "2020-09-01T12:53:41.000Z",
"body": "{
"code":"AuthenticationError",
"message":"Error authenticating with resource",
"innerError":{
"date":"2020-09-01T13:53:41",
"request-id":"652ea3be-6a97-47e8-bfc6-3d7d1d51d425"
}
}"
}
I tried also the get started projet for JS and it's working fine so I can't spot the problem.
here is what I used:
const msalConfig = {
auth: {
clientId: 'my_app_id',
redirectUri: 'http://localhost:8080'
},
cache: {
cacheLocation: "sessionStorage",
storeAuthStateInCookie: false,
forceRefresh: false
}
};
const loginRequest = { scopes: [
'openid',
'profile',
'user.read',
'calendars.read',
'User.Read.All',
'User.Export.All'
]
}
const options = new MicrosoftGraph.MSALAuthenticationProviderOptions([
'user.read',
'calendars.read',
'OnlineMeetings.ReadWrite'
]);
const onlineMeeting = {
startDateTime:"2020-09-01T16:00:34.2444915-07:00",
endDateTime:"2020-09-01T16:30:34.2464912-07:00",
subject:"test meeting"
};
const authProvider = new MicrosoftGraph.ImplicitMSALAuthenticationProvider(msalClient, options);
// Initialize the Graph client
const graphClient = MicrosoftGraph.Client.initWithMiddleware({authProvider});
// then I call this inside an async function
let events = await graphClient.api('/users/my_UserPrincipalName/onlineMeetings').post(onlineMeeting);
//let events = await graphClient.api('/me/onlineMeetings').post(onlineMeeting);
// I tried with both calls and none of them worked
and here are the permissions on azure active directory:
So any ideas on how to solve this ?
thanks

You didn't provide a correct access token.
Since Create onlineMeeting only supports Delegated (work or school account) permission type, you need to get the access token with Auth code flow or Implicit flow.
The started project for JS is using Implicit flow. So you can use Implicit flow to get the access token.
Here is the example in Postman:
The Auth URL above is https://login.microsoftonline.com/{your tenant}/oauth2/v2.0/authorize.

I figured out how to make it work in my code:
let's call my user, which I used all this time, user "A", all I did is that I simply created another user "B" in Azure Active Directory and then logging in with this new user "B" in the login screen instead of the admin user "A" that I used before..... and now it's working.
But this does not explain the issue, so if anyone can explain the difference or why it didn't work with the first account, that would be very helpful.

Related

Why all users in Strapi have access to update all users profile?

I added a new filed called config (type: json) to the User model. I use built-in swagger of Strapi local document. The problem is that I can update another user config (data) with put method.
First, I authorized by POST /auth/local and get my token and my user id (in this cast it's 5)
I add my token to swagger Authorize button.
Then, I use PUT /user/{id} in this case id is 5.
Calling api http://localhost:1337/api/users/4 returns 200!
I expect that I get 403 error! Because I should not able to change other user profiles!!!
Is it normal? If yes, tell me a solution to fix this.
This is because Strapi has only two default roles:
Public
Authenticated
So by default, when you setup permissions, whatever authentication state currently the user has access to all the content accordingly (e.g. Public to only public, Authenticated to authenticated)
To work with this, and to limit the user actions in the auth scope you have to use middleware or policy, so since this is in user-permissions scope let's add policy to user-permissions:
Strapi 4.5.3
yarn strapi generate
? Strapi Generatos
>policy
? Policy name
isOwner
? Where do you want to add this policy?
> Add policy to root of project
Next step is in your /src/extensions folder you have to create folder users-permissions, and in this folder file strapi-server.js with following content:
/src/extensions/users-permissions/strapi-server.js
module.exports = (plugin) => {
for (let i = 0; i < plugin.routes["content-api"].routes.length; i++) {
const route = plugin.routes["content-api"].routes[i];
if (
route.method === "GET" &&
route.path === "/users/:id" &&
route.handler === "user.findOne"
) {
console.log(route);
plugin.routes["content-api"].routes[i] = {
...route,
config: {
...route.config,
policies: route.config.policies
? [...route.config.policies, "global::isOwner"] // tests if policies were defined
: ["global::isOwner"],
},
};
}
}
return plugin;
};
if you did the step correct in your strapi server console you have to see:
info: In isOwner policy. if you send get request to /api/users/:id
Next step is we are going to modify policy file like so:
/src/policies/isOwner.js
"use strict";
/**
* `isOwner` policy
*/
module.exports = async (policyContext, config, { strapi }) => {
strapi.log.info("In isOwner policy.");
const { user, auth } = policyContext.state;
const { params } = policyContext;
// this case the userId is the same as the id we are requesting
// other cases would need more extensive validation...
const canDoSomething = user.id == params.id;
if (canDoSomething) {
return true;
}
return false;
};
and whoala:
{
"data": null,
"error": {
"status": 403,
"name": "PolicyError",
"message": "Policy Failed",
"details": {}
}
}
if we try to get other user profile

why messaging().sendtodevice is not working sometimes?

I'm using the following code to send a notification from one device to another using FCM. Everything works fine until before return admin.messaging().sendToDevice(...). The 'Token ID: ' log displays token ID of the receiver, but when I set the variable token_id to the sendToDevice function, the notification is not called, therefore the notification is not sent. Can someone tell me what's wrong?
var firebase = require("firebase-admin");
var serviceAccount = require("./julla-tutorial.json");
console.log("enter in then Firebase Api");
const firebaseToken = [
'e0T6j1AiRjaa7IXweJniJq:APA91bHNznSHSIey08s-C-c3gchci6wepvhP1QxQyYbmZ8LySI3wnu64iW7Q23GhA6VCdc4yodZoCFOgynfAb5C8O8VE81OcSv_LL-K3ET1IKGZ_6h35n-_q5EKFtfJWlzOqZr4IvpiB',
'dNWnSqyCQbufzv1JutNEWr:APA91bFcI9FDyRxHRBEcdw4791X0e-V0k1FjXcSstUA67l94hSojMRCd6LWr2b57azNEt3z_XLwLljMX4u2mc9cZDrAVm55Mw9CHGyue-09KofWnnHNR9XWBibc4T76xOV_DWX7T2RvW',
'cq65rtuaTCKGk5lHk7UabN:APA91bFR3kAArg6lhuBq7ktNuBk7Z9MXXk3PskqhYa8CgNaEl6MX4TQ5lo35d6XhnCQ4fEkCkyZ_j08evxE9Y4oVCRTEdqsrkccCVTE8Di47lfmDR3i1NdoL3re9oLw6F_uNsnvRoQcq'
]
firebase.initializeApp({
credential: firebase.credential.cert(serviceAccount)
})
const payload = {
notification: {
title: 'Demo 2345',
body: 'dfghj',
sound: 'default',
color: 'yellow',
android_channel_id: 'default',
channel_id: 'default'
},
data: { id: 'broadcast', channelId: 'default' }
}
const options = {
priority: 'high',
timeToLive: 60 * 60 * 24, // 1 day
};
console.log('------payload---',payload);
console.log('-----TOKEN_Array----',firebaseToken);
console.log('-------options-----',options);
firebase.messaging().sendToDevice(firebaseToken, payload, options).then(function (response) {
console.log('--------response',response);
}) .catch(function (error) {
console.log('-------rejet',reject);
});
It looks like you did not change the code from this tutorial:
https://medium.com/#jullainc/firebase-push-notifications-to-mobile-devices-using-nodejs-7d514e10dd4
you will need to change the 2nd line of code:
var serviceAccount = require("./julla-tutorial.json");
to actually point to your own firebase-push-admin.json file which holds your private keys registering your backend app with the firebase cloud messaging api. you can download this file from the firebase console as mentioned in the above article.
I recommend hiding this file from your git history by adding it to .gitignore so you dont accidentally push your private keys to a public repo.
I will link you another resource in addition to above link which helped me implement firebase push notifications in a nodeJS backend app.
https://izaanjahangir.medium.com/setting-schedule-push-notification-using-node-js-and-mongodb-95f73c00fc2e
https://github.com/izaanjahangir/schedule-push-notification-nodejs
Further I will also link you another repo where I am currently working on a fully functional firebase push notification implementation. Maybe it helps to actually see some example code.
https://gitlab.com/fiehra/plants-backend

ScopeKey doesn't work in nuxt.js auth module

Recently i started to learn how to use Nuxtjs and while learning how to use its Auth module i came across a problem.
I'm able to log in and I want to check the scope of the accounts, i tried doing it using the "scopeKey" property of "Auth". From the back end i get the "scope" from the databse and it can either be "user" or "admin".
I have tried to set the scope with
scopeKey: 'scope'
But I get that scope is "undefined"/"null" when checking with
this.$auth.hasScope('admin') / this.$auth.hasScope('user')
or "this.$auth.hasScope(admin)" return an empty value when setting "scopeKey" to
scopeKey: 'data.scope'
or
scopeKey: 'user.scope'
Here is my auth strategy:
auth: {
strategies: {
local: {
scopeKey: 'scope',
endpoints: {
login: {
url: 'api/auth/login',
method: 'post',
propertyName: 'token',
},
logout: {
url: 'api/auth/logout',
method: 'get'
},
user: {
url: 'api/me',
method: 'get',
propertyName: data
}
}
}
},
redirect: {
login: '/auth/login',
logout: '/',
callback: '/auth/login',
home: '/dash/'
}
}
and here it is an example of the json that the auth module reads when i log in:
"data": {
"id": 2,
"name": "test1",
"email": "test#test.com",
"email_verified_at": null,
"scope": "admin",
"created_at": "2019-08-01 13:11:49",
"updated_at": "2019-08-01 13:11:49"
},
I can access the scope value on the front end page with
$auth.user.scope
or with
$auth.$state.user.scope
But how can I give the "scope" to the "scopeKey" property in the nuxt.config.js file while setting the "auth" properties/strategy?
edit:
I have tried moving it inside the auth object or deleting the property and I still get false on $auth.hasScope('admin') and $auth.hasScope('user') which means scopeKey is still undefined and i'm not sure why.
The scopeKey is 'scope' by default. You don't need to set it again.
For me it worked by doing server side change.
When I put string value in scope, it does not work
$data['scope'] = "admin";
But when I changed it to array, $auth.hasScope('admin') works;
$data['scope'] = array("admin", "test");
Hope it helps.
scopeKey: 'scope' should not be placed inside strategies object.
Put it directly in the auth object.
Take a look at default config.
P.S. You can even delete this property from your auth config object, because 'scope' is default value for scopeKey.
Somehow hasScope() is not working for me too, so I directly checked the user object, I also has token in my response.
I am having a type variable in my response that tells me if the user is admin or someone else.
add this into your middleware
export default function ({ $auth, redirect }) {
if (!$auth.loggedIn) {
return redirect('/')
}
if ($auth.user.type != 'Super Admin') { // Super Admin or whatever the user you want to check
return redirect('/')
}
}

Parse-server social login

I am developing application based on Parse-server and I want to offer social login. I found this guide in the documentation http://docs.parseplatform.org/js/guide/#linking-users.
I started to implement the social login by google. I did following steps:
1) I added following lines to the ParseServer settings
var api = new ParseServer({
...
auth:{
google: {}
},
...
});
2) I did the authentication by hello.js on the client side (call user._linkWith function on login)
hello.init({
google: 'My Google id'
});
hello.on('auth.login', function(auth) {
// Call user information, for the given network
hello(auth.network).api('me').then(function(r) {
const user = new Parse.User();
user._linkWith(auth.network, auth.authResponse).then(function(user){
console.log('You are logged in successfully.');
});
});
});
When I debugged it, I found that it fails in _linkWith() function, when provider object is preparing. Object AuthProviders, which should store all providers, is empty. Because of it the statement provider = authProviders['google']; leads to undefined. Invoking provider.authenticate(...); leads to error "Cannot read property 'authenticate' of undefined"
What am I missing or what am I doing wrong?
Thanks for all your answers.
Honza
Did you register the authenticationProvider? You can find examples in our unit tests on how to do so:
https://github.com/parse-community/parse-server/blob/5813fd0bf8350a97d529e5e608e7620b2b65fd0c/spec/AuthenticationAdapters.spec.js#L139
I also got this error and looked at the _linkWith(provider, options) source code. It checks if options has an authData field (which in turn should contain id and credentials). If so, it uses options.authData. Otherwise it falls back on looking up a previously registered authentication provider mentioned in the previous answer.
This is a fragment of the code I'm using:
const authData = {
"id": profile.getId(),
"id_token": id_token
}
const options = {
"authData": authData
}
const user = new Parse.User();
user._linkWith('google', options).then(function(user) {
console.log('Successful user._linkWith(). returned user=' + JSON.stringify(user))
}, function(error) {
console.log('Error linking/creating user: ' + error)
alert('Error linking/creating user: ' + error)
// TODO handle error
})

How to use servicebus topic sessions in azure functionapp using javascript

I have an Azure Functionapp that processes some data and pushes that data into an Azure servicebus topic.
I require sessions to be enabled on my servicebus topic subscription. I cannot seem to find a way to set the session id when using the javascript functionapp API.
Here is a modified extract from my function app:
module.exports = function (context, streamInput) {
context.bindings.outputSbMsg = [];
context.bindings.logMessage = [];
function push(response) {
let message = {
body: CrowdSourceDatum.encode(response).finish()
, customProperties: {
protoType: manifest.Type
, version: manifest.Version
, id: functionId
, rootType: manifest.RootType
}
, brokerProperties: {
SessionId: "1"
}
context.bindings.outputSbMsg.push(message);
}
.......... some magic happens here.
push(crowdSourceDatum);
context.done();
}
But the sessionId does not seem to get set at all. Any idea on how its possible to enable this?
I tested sessionid on my function, I can set the session id property of a message and view it in Service Bus explorer. Here is my sample code.
var connectionString = 'servicebus_connectionstring';
var serviceBusService = azure.createServiceBusService(connectionString);
var message = {
body: '',
customProperties:
{
messagenumber: 0
},
brokerProperties:
{
SessionId: "1"
}
};
message.body= 'This is Message #101';
serviceBusService.sendTopicMessage('testtopic', message, function(error)
{
if (error)
{
console.log(error);
}
});
Here is the test result.
Please make sure you have enabled the portioning and sessions when you created the topic and the subscription.

Categories

Resources