Microsoft Graph example snippets for JavaScript not working - javascript

I've been following this tutorial with this library, but the code snippets provided are producing errors. I have registered the app with Azure and followed the instructions, but when I run the code, it says SyntaxError: await is only valid in async functions and the top level bodies of modules at /script.js:74:20
Here's a relevant snippet of code, but if you have Replit, I would really appreciate it if you could collaborate with me on my Repl instead.
Replit link: https://replit.com/join/rgqcqfcohh-5pengoo
Code:
const msal = require('#azure/msal-node');
// Create msal application object
const cca = new msal.ConfidentialClientApplication(config);
const REDIRECT_URI = "http://localhost:3000/redirect";
const config = {
auth: {
clientId: "ebcb2e8c-4675-411f-a76e-25aafe0c026d",
authority: "https://login.microsoftonline.com/98ca2106-858a-413a-b7d5-31301dcf9869/",
// I wasn't sure if this meant the key value or the secret ID
clientSecret: "ee10b5ce-f9c4-460a-a402-064030841f86"
},
system: {
loggerOptions: {
loggerCallback(loglevel, message, containsPii) {
console.log(message);
},
piiLoggingEnabled: false,
logLevel: msal.LogLevel.Verbose,
}
}
};
// 1st leg of auth code flow: acquire a code
app.get('/', (req, res) => {
const authCodeUrlParameters = {
scopes: ["user.read"],
redirectUri: REDIRECT_URI,
};
// get url to sign user in and consent to scopes needed for application
pca.getAuthCodeUrl(authCodeUrlParameters).then((response) => {
res.redirect(response);
}).catch((error) => console.log(JSON.stringify(error)));
});
// 2nd leg of auth code flow: exchange code for token
app.get('/redirect', (req, res) => {
const tokenRequest = {
code: req.query.code,
scopes: ["user.read"],
redirectUri: REDIRECT_URI,
};
pca.acquireTokenByCode(tokenRequest).then((response) => {
console.log("\nResponse: \n:", response);
res.sendStatus(200);
}).catch((error) => {
console.log(error);
res.status(500).send(error);
});
});
try {
let userDetails = await client.api("/me").get();
console.log(userDetails);
} catch (error) {
throw error;
}

MohammedMehtabSiddiqueMINDTREELIMI-9821 on the Microsoft Docs informed me that...
"You can use "await" only inside a function which is "async".
Here you can try remove 'await' from the code and try to run it"
and it worked!

Related

oauth authorization and token not functioning as expected in JS script

My application uses the Zoom API with OAuth.
The process is well put in the zoom developer docs and I followed them
I created a zoom app in the developer's account and got the clientID and clientSecret.
First we need to get the Authorization code from "https://zoom.us/oauth/authorize". With this code we can get the access token from "https://zoom.us/oauth/token". Pretty straight forward. I tried it on Postman and all the APIs work.
My JS code below doesn't work and keeps failing to do this task.
const express = require('express');
const axios = require('axios');
let token = null;
const app = express();
const clientId = 'ADqR4l7KTfMmXXXXXXXX';
const clientSecret = 'mhVytefIFS4fSqQ3XXXXXXXXXX';
const redirectURL = 'http://localhost:3000/oauth-callback'
app.get('/', (req, res) => {
res.redirect(`https://zoom.us/oauth/authorize?response_type=code&client_id=${clientId}&redirect_uri=${redirectURL}`);
});
app.get('/oauth-callback', (req, res) => {
const body = {
client_id: clientId,
client_secret: clientSecret,
code: req.query.code
};
const opts = { headers: { accept: 'application/json' } };
axios.post(`https://zoom.us/oauth/token`, body, opts).
then(res => res.data['access_token']).
then(_token => {
console.log('My token:', token);
token = _token;
res.json({ ok: 1 });
}).
catch(err => res.status(500).json({ message: err.message }));
});
app.listen(3000);
console.log('App listening on port 3000');
zoom dev acct:
zoom dev account
Error message:
Error message
How can I get the access token? Please help me find my errors in the code.

getPSTNcall Javascript error Microsoft graph

I am able to get acesstoken with all the scope but when I add CallRecord-PstnCalls.Read.All, CallRecords.Read.All to scopes it gives me error
msal-browser.min.js:35 Uncaught (in promise) ServerError: invalid_client: AADSTS650053: The application 'postman' asked for scope 'CallRecord-PstnCalls.Read.All' that doesn't exist on the resource '00000003-0000-0000-c000-000000000000'. Contact the app vendor.
Trace ID: f7f4e4a5-078d-4aaf-bee7-c0c61f9f8e00
Correlation ID: 66ccba3c-fce0-4c40-8b00-83060b9defc3
Timestamp: 2021-12-28 13:24:30Z
the following is my code.Please help me my boss needs this done today.I have all the permission in azure for PSTN
const express = require('express')
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.send('Hello World!')
});
app.listen(port, () => {
console.log(`Example app listening on port ${port}!`)
});
async function run(){
const config = {
auth: {
clientId: '1be18c1a-5a3d-43ac-a953-5e04c6b8a93f',
authority: 'https://login.microsoftonline.com/organizations/',
redirectUri: 'http://localhost:8080'
}
};
var client = new msal.PublicClientApplication(config);
var loginRequest = {
scopes: ['CallRecord-PstnCalls.Read.All','CallRecords.Read.All']
};
let loginResponse = await client.loginPopup(loginRequest);
console.log('Login Response', loginResponse);
var tokenRequest = {
scopes: ['CallRecord-PstnCalls.Read.All','CallRecords.Read.All' ],
account: loginResponse.account
};
let tokenResponse = await client.acquireTokenSilent(tokenRequest);
console.log('Token Response', tokenResponse);
let payload = await fetch("https://graph.microsoft.com/v1.0/communications/callRecords/getPstnCalls(fromDateTime=2019-11-01,toDateTime=2019-12-01)", {
headers: {
'Authorization': 'Bearer ' + tokenResponse.accessToken
}
});
let json = await payload.json();
console.log('Graph Response', json);
}
Mainly this issue occurs if the scopes are not added in your App registration. Please make sure that it is added to correct app registration and permission is granted by an admin.
Please follow this link to call an API using MSAL -
Acquire token.
For you further reference we are adding a sample link where we are using MSAL flow to call Graph.
https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/v-nikija/tab-sso-obo-update/samples/tab-sso/nodejs/src/server/tabs.js
Please refer above sample and in authority can you specify the tenantId -
authority: "https://login.microsoftonline.com/${your_tenant_Id}".

Google oAuth2 UnhandledPromiseRejectionWarning: Error: No refresh token is set

This below is my auth.js route code to login via oAuth2 and it was working till this afternoon, now tonight started to throw error UnhandledPromiseRejectionWarning: Error: No refresh token is set.
const express = require("express");
const google = require('googleapis').google;
const jwt = require('jsonwebtoken');
const CONFIG = require("../config/passport-google");
const nf = require('node-fetch');
const gUser = require('../models/User-g');
const router = express.Router();
// Google's OAuth2 client
const OAuth2 = google.auth.OAuth2;
router.get("/youtube", function(req, res) {
// Create an OAuth2 client object from the credentials in our config file
const oauth2Client = new OAuth2(
CONFIG.oauth2Credentials.client_id,
CONFIG.oauth2Credentials.client_secret,
CONFIG.oauth2Credentials.redirect_uris[0]
);
// Obtain the google login link to which we'll send our users to give us access
const loginLink = oauth2Client.generateAuthUrl({
access_type: "offline", // Indicates that we need to be able to access data continously without the user constantly giving us consent
scope: CONFIG.oauth2Credentials.scopes // Using the access scopes from our config file
});
return res.render("./home/g-login", { loginLink: loginLink });
});
router.get("/youtube/callback", function(req, res) {
// Create an OAuth2 client object from the credentials in our config file
const oauth2Client = new OAuth2(
CONFIG.oauth2Credentials.client_id,
CONFIG.oauth2Credentials.client_secret,
CONFIG.oauth2Credentials.redirect_uris[0]
);
if (req.query.error) {
// The user did not give us permission.
return res.redirect("/");
} else {
oauth2Client.getToken(req.query.code, function(err, token) {
if (err) return res.redirect("/");
// Store the credentials given by google into a jsonwebtoken in a cookie called 'jwt'
res.cookie("jwt", jwt.sign(token, CONFIG.JWTsecret));
// return res.redirect("/get_some_data");
if (!req.cookies.jwt) {
// We haven't logged in
return res.redirect("/");
}
// Add this specific user's credentials to our OAuth2 client
oauth2Client.credentials = jwt.verify(req.cookies.jwt, CONFIG.JWTsecret);
// Get the youtube service
const service = google.youtube("v3");
const url = `https://www.googleapis.com/oauth2/v1/userinfo?access_token=${token[Object.keys(token)[0]]}`;
const get_data = async () => {
try {
const response = await nf(url);
const json = await response.json();
// save user to db
async (json, done) => {
const newUser = {
channelId: json.id,
channelEmail: json.email,
image: json.picture,
createdAt: Date.now()
}
try {
let user = await gUser.findOne({ channelId: json.id });
if(user){
done(null, user);
} else {
user = await gUser.create(newUser);
done(null, user);
}
} catch (err) {
console.log(err);
return res.redirect("../../500");
}
}
return json;
} catch (err) {
console.log(err);
return res.redirect("../../500");
}
};
// Get 50 of the user's subscriptions (the channels they're subscribed to)
service.subscriptions
.list({
auth: oauth2Client,
mine: true,
part: "snippet,contentDetails",
maxResults: 50
})
.then(async (response) => {
//.then(response => {
const diomerda = await get_data();
// Render the profile view, passing the subscriptions to it
return res.render("./user/dashboard", { subscriptions: response.data.items, diomerda: diomerda });
});
});
}
});
// Logout from Google
router.get('/logout', (req, res) => {
req.logout();
res.redirect('/');
})
module.exports = router;
I tried to delete the app from the authorized apps inside my google account im using to test, and when i test the login again it now goes through all the steps of the login, it asks for permit, i accept twice and then it throws that error and the page looks like frozen in a loop

How do I unit test a function that needs a cookie with Jest?

I'm very new to testing and I can't figure out how to test this scenario. I use supertest and Jest for testing. In my Express app I use jwt authentication. I store a jwt token that identifies a user in a http only cookie, and it's been created when a user creates and account or logs in.
Now, I have a route that is responsible for a password change requested by a user:
router.post('/reset-password', async function (req, res, next) {
try {
//relevant to the question part here
//
const { userToken } = req.cookies
if (!userToken) {
res.status(401).json({ error: 'unauthorized' })
return
}
const { email } = jwt.verify(userToken, process.env.JWT_SECRET)
/////////////////////
} catch (err) {
res.status(401).json({ error: 'unable to verify' })
}
})
As I understand, in order to test this function, I need to set a cookie in beforeAll. I tried doing so by registering a user that normaly sets required token. Here is my test code:
const request = require('supertest')
const app = require('../app')
const MongoClient = require('mongodb').MongoClient
const client = new MongoClient(`mongodb://localhost:27017/img-test`, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
beforeAll(async () => {
await client.connect()
app.locals.db = client.db('img-test')
await request(app).post('/register').send({
username: 'Bob',
email: 'bob#email.com',
password: 'Hardpass0!',
checkboxTerms: 'on',
'g-recaptcha-response': 'asdasd',
})
})
describe('Password reset', () => {
test('Should reset password', async () => {
await request(app)
.post('/api/account/reset-password')
.send({
passwordCurrent: 'Hardpass0!',
passwordNew: 'Hardpass1!',
})
.expect(200)
})
})
afterAll(async () => {
let db = app.locals.db
await db.dropDatabase()
client.close()
})
And of course, it fails. userToken is going to be undefined because as I understand supertest is not setting an http only cookie when a user is registered, and there is no token on req.cookies? How do I test this scenario? What am I doing wrong? Thanks for help.

JWT Login - No authorization token was found in middleware

I followed a tutorial to add login and registration to my Node.js app using JWT token and I'm having a hard time logging in and redirecting to my 'logged in' admin page. User registration works great, but the login portion I can't figure out.
This is the tutorial I was following:
https://medium.freecodecamp.org/learn-how-to-handle-authentication-with-node-using-passport-js-4a56ed18e81e
My code for login looks like this:
router.post('/login', auth.optional, (req, res, next) => {
console.log(req.body);
var user = {
email: req.body.email,
password: req.body.password
}
if (!user.email) {
return res.status(422).json({
errors: {
email: 'is required',
},
});
}
if (!user.password) {
return res.status(422).json({
errors: {
password: 'is required',
},
});
}
return passport.authenticate('local', { session: false }, (err, passportUser, info) => {
if (err) {
return next(err);
}
if (passportUser) {
const user = passportUser;
user.token = passportUser.generateJWT();
console.log("TOKEN: " + user.token);
res.setHeader('Authorization', 'Token ' + user.token);
return res.json({ user: user.toAuthJSON() });
}
return res.status(400).json({
errors: {
message: info,
},
});
})(req, res, next);
});
My '/admin' "logged in" route looks like this:
router.get("/admin", auth.required, function(req, res) {
res.render('admin', {
user : req.user // get the user out of session and pass to template
});
});
I'm not sure how I can redirect to my '/admin' route while also passing the token because currently I am seeing the following error after logging in. Makes sense since I am not passing the token to the '/admin' route...but how do I do that? :)
UnauthorizedError: No authorization token was found at middleware
Thanks in advance for the help!
EDIT:
Still can't figure this out and don't really understand how this flow is supposed to work...where do the headers need to be set to the token and how do I redirect to my admin page once the login is successful.
Here is my middleware code if this helps:
const getTokenFromHeaders = (req) => {
console.log("REQ: " + JSON.stringify(req.headers));
const { headers: { authorization } } = req;
if(authorization && authorization.split(' ')[0] === 'Token') {
return authorization.split(' ')[1];
}
return null;
};
const auth = {
required: jwt({
secret: 'secret',
userProperty: 'payload',
getToken: getTokenFromHeaders,
}),
optional: jwt({
secret: 'secret',
userProperty: 'payload',
getToken: getTokenFromHeaders,
credentialsRequired: false,
}),
};
Your code does not have a problem. You seem to be confused with the login flow from server to client (Frontend/Web).
Let's first have a look the RESTFUL way of doing it. The article also refers to the same flow.
The RESTFUL API flow looks like this:
User requests for login:
POST: /api/v1/auth/login with username and password in request body.
If successful, user is returned with basic inforamtion and token.
If not, user is returned a 401 (Unauthorized) status code.
The login flow ends here.
The token provided earlier to the user is used to make subsequent calls to the backend, which a user can use to perform different operations on the sustem. In essence, it is the client which requests server for subsequent actions with the token provided in the login request.
So for your case, user after receiving the token should make a request for retrieving admin information from the backend.
But, I am assuming you are rendering views from your server-side and you want to render the admin view once the user is successfully logged in, and that's pretty straight forward.
Instead of your res.json() after successful login. You need to use res.render().
res.render('admin', {
user: user.toAuthJSON() // assuming your user contains the token already
})
Edit:
Since res.render() does not change the url in the browser. For that, you need to use res.redirect(). But the problem is, you can not send context in res.redirect().
To achieve that, you will need to pass in the user token as query paramter. See here.
TL;DR
// assuming you are using Node v7+
const querystring = require('querystring');
const query = querystring.stringify({
token: user.token,
});
const adminRoute = '/admin?' + query;
res.redirect(adminRoute)
And in your admin route, you need to slightly modify the code.
Verify the token belongs to a real user and get user information out of the token.
Render the admin template with user information retrieved from step 1.
router.get("/admin", function(req, res) {
// verify the token
const token = req.query.token;
const user = null;
jwt.verify(token, 'secret', function (err, decoded) {
if (err) {
res.status(401).send('Unauthorized user')
}
// decoded contains user
user = decoded.user
});
res.render('admin', {
user : user
});
});
I'm somewhat new to this as well, but I've got it working as follows.
In your server.js file:
const passport = require("passport");
const JwtStrategy = require("passport-jwt").Strategy;
const ExtractJwt = require("passport-jwt").ExtractJwt;
app.use(passport.initialize());
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = Keys.secretOrKey;
passport.use(
new JwtStrategy(opts, (jwt_payload, done) => {
// somefunction looks up the id in jwt payload and
// supplies passport the authenticated user via the "Done" function
somefunction.user(jwt_payload.id)
.then(user => {
if (user) {
return done(null, user);
}
return done(null, false);
});
})
);
In your API definitions
const jwt = require("jsonwebtoken");
router.post("/login", (req, res) => {
const { userInfo } = req.body;
// userInfo has username and password in it
// anotherFuction validates the user id and password combo
anotherFunction(userInfo.id, userInfo.password)
.then(isAuthenticated => {
if (isAuthenticated) {
const payload = {
id: user.sAMAccountName,
firstname: user.givenName,
lastname: user.sn
};
// Sign Token with the payload
jwt.sign(
payload,
Keys.secretOrKey,
{ expiresIn: 3600 },
(err, token) => {
res.json({
success: true,
token: "Bearer " + token
});
}
);
} else {
// don't mind the statuses ^_^'
return res.status(401).json({ error: "Login failed." });
}
})
.catch(err => {
return res.status(400).json(err);
});
});
After calling the API you want to set the auth token. The following lets you delete the token if nothing is passed in, effectively "Logging out".
const setAuthToken = token => {
if (token) {
// Apply to every request
axios.defaults.headers.common["Authorization"] = token;
} else {
// Delete Auth Header
delete axios.defaults.headers.common["Authorization"];
}
};
If you're trying to use it in the front end, you need to use jwt_decode to pull the values from the token and set it however you deem necessary. If using redux to store login data it should look something like this. As I feel that the discussion of using localstorage for jwtToken is outside of the scope of this, just know would need to check for the token.
if (localStorage.jwtToken) {
setAuthToken(localStorage.jwtToken);
const decoded = jwt_decode(localStorage.jwtToken);
store.dispatch({
type: USER_LOGIN,
payload: decoded
});
}
Hope this helped.
From one beginner in JWT to another. Good luck.

Categories

Resources