Msgraph Client request hangs or returns 401 error after obtianing token and send request

ian 1 Reputation point
2022-04-12T03:04:17.4+00:00

I'm trying to make a basic authentication flow that logs the user in and make an http request to the Microsoft Graph API. I have obtained the token from the MSAL library helper functions, and granted the right permissions for my application on admin console in Azure Active Directory, but I always see the 401 error "missing valid authentication token" upon making an http request to the graph API, like "/me/onenote/notebook"

Here's my code:

const express = require("express");
const msal = require('@azure/msal-node');
const graph = require('@microsoft/microsoft-graph-client');
require('isomorphic-fetch');
require('dotenv').config();

const session = require('express-session')

const SERVER_PORT = process.env.PORT || 3000;
const REDIRECT_URI = process.env.OAUTH_REDIRECT_URI;

// Create Express App and Routes
const app = express();

app.use(session({
    secret:'sec-key',
    resave: false,
    saveUninitialized: false,
    unset: 'destroy'
}));

// Before running the sample, you will need to replace the values in the config, 
// including the clientSecret
const config = {
    auth: {
        clientId: process.env.OAUTH_CLIENT_ID,
        authority: process.env.OAUTH_AUTHORITY,
        clientSecret: process.env.OAUTH_CLIENT_SECRET
    },
    system: {
        loggerOptions: {
            loggerCallback(loglevel, message, containsPii) {
                console.log(message);
            },
            piiLoggingEnabled: false,
            logLevel: msal.LogLevel.Verbose,
        }
    }
};

// Create msal application object
const pca = new msal.ConfidentialClientApplication(config);
//store msalClient in expressjs in-memory cache for global use
app.locals.msalClient = pca;

app.get('/', (req, res) => {
    const authCodeUrlParameters = {
        scopes: process.env.OAUTH_SCOPES.split(','),
        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)));
});

function getAuthenticatedClient(msalClient, userId) {
  if (!msalClient || !userId) {
    throw new Error(
      `Invalid MSAL state. Client: ${msalClient ? 'present' : 'missing'}, User ID: ${userId ? 'present' : 'missing'}`);
  }

  // Initialize Graph client
  const client = graph.Client.init({
    // Implement an auth provider that gets a token
    // from the app's MSAL instance
    authProvider: async (done) => {
      try {
        // Get the user's account
        const account = await msalClient
          .getTokenCache()
          .getAccountByHomeId(userId);

        if (account) {
          // Attempt to get the token silently
          // This method uses the token cache and
          // refreshes expired tokens as needed
          const response = await msalClient.acquireTokenSilent({
            scopes: process.env.OAUTH_SCOPES.split(','),
            redirectUri: process.env.OAUTH_REDIRECT_URI,
            account: account
          });

          // First param to callback is the error,
          // Set to null in success case
          done(null, response.accessToken);
        }
      } catch (err) {
        console.log(JSON.stringify(err, Object.getOwnPropertyNames(err)));
        done(err, null);
      }
    }
  });

  return client;
}

//working OK, got the auth token from the ?code param and saved in memory session
app.get('/auth/callback', (req, res) => {
    const tokenRequest = {
        code: req.query.code,
        //TODO: look into one note scopes for every function init
        scopes: process.env.OAUTH_SCOPES.split(','),
        redirectUri: REDIRECT_URI,
    };

    pca.acquireTokenByCode(tokenRequest).then((response) => {
        req.session.token = response;
        console.log(req.session.token);
        req.session.userId = response.account.homeAccountId;
        console.log(req.session.userId);
        res.sendStatus(200);
    }).catch((error) => {
        console.log(error);
        res.status(500).send(error);
    });
});

// having isues with 401 error, or code -1 unauthorized permission or missing auth token,. Prob a user permission thing on Azure AD or scope in .env or sth
app.get('/onenote',(req,res)=>{
  const apiTok = getAuthenticatedClient(pca, req.session.userId)
    .api('/me/onenote/notebooks')
    .get()
    .catch((err)=> console.error(err));
  console.log(apiTok);
})

app.get('/signout',(req,res)=>{
  req.session.destroy((info)=> console.log('signed out', info))
})

app.listen(SERVER_PORT, () => console.log(`Msal Node Auth Code Sample app listening on http://localhost:${SERVER_PORT}`))
Microsoft Graph
Microsoft Graph
A Microsoft programmability model that exposes REST APIs and client libraries to access data on Microsoft 365 services.
11,125 questions
{count} votes