I am using node.js and the Microsoft Graph npm package (#microsoft/microsoft-graph-client)for calling webhook in office 365 for calendar events. I am receiving multiple webhook notifications for every Office 365 calendar event update, delete and create.
My source code is
router.post("/webhook", (req, res) => {
if (req.query.validationToken) {
res.status(200);
res.send(req.query.validationToken)
} else {
res.status(202);
console.log(req.body.value[0].changeType);
console.log(req.body.value[0].resource);
}
});
//CREAE A WEBHOOK
router.get("/createWebhook", async (req, res) => {
const accessToken = await authHelper.getAccessToken(req.cookies, res);
const client = graph.Client.init({
authProvider: (done) => {
done(null, accessToken);
}
});
const subscription = {
changeType: "deleted,updated,created",
notificationUrl: "https://abccb3e5.ngrok.io/calendar/webhook",
resource: "me/events",
expirationDateTime: "2020-01-26T18:23:45.9356913Z",
clientState: "My calendar sync"
};
try {
client.api('/subscriptions')
.post(subscription, (errr,result) => {
if (result)
console.log(result);
//process subscription
});
} catch (err) {
console.log(err)
}
res.redirect('/calendar');
});
When I create an event, Graph notifies multiple times in post webhook endpoint and then continues for deletes and updates also.
This is by design, the Microsoft Graph Webhooks service can send you duplicate notifications for the same events.
Your code needs to handle this scenario, some notifications carry a unique id to help you keep tracks of the deliveries
Related
I have a login form with username and password. I'm trying to validate these credentials using the Nest Js authentication strategy here. So in the corresponding auth.service.ts file, I'm using "nativescript core modules http" to do a POST request to OAuth URL to validate credentials . But this doesn't work:
import { Injectable } from '#nestjs/common';
import { request } from "tns-core-modules/http";
const OAUTH_URL = 'url';
#Injectable()
export class AuthService {
async validateUser(username: string, password: string): Promise<any> {
let data = new FormData();
data.set('client_id', 'sb-nestjs-app!t36258');
data.set('client_secret', 'XrHuBRhyvuVNYNJNHlWLgcuBIyc=');
data.set('username', username);
data.set('password', password);
data.set('grant_type', 'password');
data.set('response_type', 'token');
request({
url: OAUTH_URL,
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json;charset=utf8"
},
content: data
}).then((response) => {
console.log('response => ' + response + ' statuscode ' + response.statusCode);
if (response.statusCode == 200) {
const token = response.content['access_token'];
//TODO:
// need to send scope also
return token;
}
}, (e) => {
console.log('error' + e);
return null;
});
return null;
}
}
When I run 'nest start' after above code in place, I receive Error: Cannot find module './http-request'
I'm not sure what is going here, I tried "npm install http-request" it didn't work either. Basically, I need to POST credentials to a OAuth url in NestJs. Any guidance? Thank you.
Try with HttpModule from NestJS.
Also you can try request from npm, but they deprecated this package. From what I saw on their discussion, the package still works but you will not have support for it, or anything. Here are some alternatives to it .
I'm not sure you are using the correct request npm module. I'm talking about:
import { request } from "tns-core-modules/http"
Good Luck!
I have a simple electron app that wraps around a web app. The web app prompts for user name but electron doesn't show the prompt and directly goes to the 401 Authorization Required page. Is there a setting I need to change to make the prompt show? I can't seem to find it in the documentation. Any help is appreciated.
const { app, BrowserWindow } = require('electron');
function createWindow() {
browserWindow = new BrowserWindow({});
browserWindow.loadURL('https://domain')
}
app.on('ready', createWindow);
Listen to this "login" event.
Create your own prompt. For example, create a browser window which loads an HTML form and when the user fills the username and password fields pass the credentials back via ipc calls to the callback.
app.on("login", (event, webContents, request, authInfo, callback) => {
event.preventDefault();
createAuthPrompt().then(credentials => {
callback(credentials.username, credentials.password);
});
});
function createAuthPrompt() {
const authPromptWin = new BrowserWindow();
authPromptWin.loadFile("auth-form.html"); // load your html form
return new Promise((resolve, reject) => {
ipcMain.once("form-submission", (event, username, password) => {
authPromptWin.close();
const credentials = {
username,
password
};
resolve(credentials);
});
});
}
I have a Umbraco website that has google sign in button configured as follows:
At the top of the page (inside the header section) I have the scripts for calling google API:
<script src="https://apis.google.com/js/client:platform.js?onload=start" async defer></script>
<script>
function start() {
gapi.load('auth2', function() {
auth2 = gapi.auth2.init({
client_id: '<myapp client Id>.apps.googleusercontent.com',
// Scopes to request in addition to 'profile' and 'email'
redirect_uri: 'http://localhost:40136/umbraco/Surface/AuthSurface/GoogleAuthrizedUser',
scope: 'profile email'
});
});
}
</script>
In the body section of the code I have the google button setup and associated click function:
<script>
function onSignIn(authResult) {
if (authResult['code']) {
var authCode = authResult['code'];
console.log("Authorization Code: " + authCode);
$.post("/umbraco/Surface/AuthSurface/GoogleAuthrizedUser", { code: authCode })
.done(function(msg) {
// Success settings
})
.fail(function(xhr, status, error) {
});
} else {
//authResult['code'] is null
//handle the error message.
}
};
</script>
Controller code that handles the call back on the server end:
public class AuthSurfaceController : SurfaceController
{
public ActionResult GoogleAuthrizedUser()
{
string AuthCode = HttpContext.Request["code"];
var info = new GoogleAccessTokenResponse();
var client = new GoogleOAuthClient();
try
{
info = client.GetAccessTokenFromAuthorizationCode(AuthCode);
}
catch (Exception ex)
{
var strMessage = String.Format("<div class=\"info\"><p>{0}</p><p>{1}</p></div>", "Google Login Error",
ex.Message);
return Json(new AjaxOperationResponse(false, strMessage));
}
}
}
On the Serverside I am using Skybrud Social plugin for accessing google apis.
The google authentication happens in the popup and authorizes client with credentials and authResult['code'] has a valid code.
In the controller when I initialize the client and call the function GetAccessTokenFromAuthorizationCode(AuthCode), it returns an exception of 'Invalid Request'
I tried checking this authResult['code'] returned in the javascript function onSignIn in the https://developers.google.com/oauthplayground/
Same error description is shown 'Invalid request'. I am not sure why this is happening. The error returned is "invalid_grant"
Can anyone have a solution to this problem? What am I doing wrong here?
In your surface controller you're initializing a new instance of GoogleOAuthClient, but without setting any of the properties. The GetAccessTokenFromAuthorizationCode method requires the ClientId, ClientSecret and RedirectUri properties to have a value. You can initialize the properties like this:
// Initialize a new instance of the OAuth client
GoogleOAuthClient oauth = new GoogleOAuthClient {
ClientId = "The client ID of your project",
ClientSecret = "The client secret of your project",
RedirectUri = "The return URI (where users should be redirected after the login)"
};
You can read more about authentication in the documentation: http://social.skybrud.dk/google/authentication/ (the approach explained there will however not use any JavaScript)
I have a Web Api Application which has the following question.
[HttpGet]
[Route("Account/userName{userName}/password={password}/rememberMe/{rememberMe}")]
public HttpResponseMessage LogIn(string userName, string password, bool rememberMe)
{
if (User.Identity.IsAuthenticated)
{
return Request.CreateResponse(HttpStatusCode.Conflict, "already logged in.");
}
var dbPerson = dbContext.Persons.Where(x => x.UserName.Equals(userName) && x.EncryptedPassword.Equals(password)).FirstOrDefault();
if (dbPerson != null)
{
FormsAuthentication.SetAuthCookie(userName, rememberMe);
return Request.CreateResponse(HttpStatusCode.OK, "logged in successfully");
}
else
{
return new HttpResponseMessage(HttpStatusCode.Unauthorized);
}
}
I am calling from another MVC project. I Got the authentication but very next page where I am calling the ajax method
var uri = 'http://localhost:44297/api/XXXX';
$(document).ready(function () {
// Send an AJAX request
$.getJSON(uri)
.done(function (data) {
// On success, 'data' contains a list of products.
for (var i = 0; i < data.$values.length; i++)
{
}
})
.fail(function() {
console.log( "error" )});
});
I am getting GET http://localhost:44297/api/StudyFocus 401 (Unauthorized). how I can solve this issue. I know I need to pass some cookie/session value with this ajax call. but I don't know how. can anyone explain me with example.
My application relies on web Api project including authentication. I need to make web api application secure using form authentication. Any help is highly appreciable. Thanks
You can't authenticate web api by the use of cookies or session. You need access token to do that.
Follow this tutorial for the implementation http://www.asp.net/web-api/overview/security/individual-accounts-in-web-api
var accountSid = 'AC066a9b14a2a701b556491953c1827f84';
var authToken = "{{ auth_token }}";
var client = require('twilio')(accountSid, authToken);
client.messages.list(function(err, data) {
data.messages.forEach(function(message) {
console.log(message.body);
});
});
Twilio says I can filter the messages by using From or To parameter but the document lacks the details. I want to retrieve messages that are sent from 123. How do I do it?
client.messages.list({
from: "34234234",
}, function(err, data) {
data.messages.forEach(function(message) {
console.log(message.friendlyName);
});
});
I had to go to the API playground.