Angular/NodeJS share frontend access token to fetch data from MS graph by backend

Viewed 391

I have a small MEAN stack running (Angular in Frontend and NodeJS in Backend). The Frontend is protected by MSAL (@azure/msal-angular).

This part is working fine. The user gets authorized for the frontend and Angular is able to request data from MS Graph (the msal interceptor adds the token to all requests to the MS Graph and the backend):

app.module.ts

MSalModule.forRoot( new PublicClientApplication({ // MSAL Configuration
  auth: {
    clientId: environment.aad_client_id,
    authority: 'https://login.microsoftonline.com/' + environment.aad_tenant_id + '/',
    redirectUri: window.location.origin,
  },
  cache: {
    cacheLocation : BrowserCacheLocation.LocalStorage,
    storeAuthStateInCookie: isIE,
  }
}), {
  // MSAL Guard Configuration
  interactionType: InteractionType.Redirect, 
  authRequest: {
    scopes: ['user.read', environment.aad_scope_api]
  }
}, {
  // MSAL Interceptor Configuration
  interactionType: InteractionType.Redirect, 
  protectedResourceMap: new Map([
    ['https://graph.microsoft.com/v1.0', ['user.read']],
    [environment.apiUrl, [environment.aad_scope_api]],
  ])
})

After redirect from MS login I send a post request to my NodeJS Backend to establish a session. The login route of the Backend should extract the token from the header, and send some request to the graph, to store the user details from there in the user session.

login.js

router.post('/login', (req, res) => {
  if (req.session.user) {
      res.json(req.session.user);
  } else {
      fetchUser(req, mongodb).then(result => {
          req.session.user = result;
          res.json(result);
      }).catch(err => {
          res.status(401).json(err);
      })
  }
});

...

async function fetchUser(token) {
  try {
    const token = req.headers.authorization;
    request({
        headers: { 'Authorization': token },
        uri: 'https://graph.microsoft.com/v1.0/me',
        method: 'GET'
    }, { json: true }, (err, res, body) => {
        if (err) { throw err; }
        const obj = ...do some things
        return obj;
    });
  } catch(err) {
    throw err;
  }
}

The issue is, that the token is only valid from Frontend. MS recommend the on-behalf-of-flow for that, but I'm not able to find any way to solve this. So how can I request a new token for my backend?

1 Answers

You can request a token for the backend to access Graph using the client credentials authentication, and set the scopes for Graph as Application Permissions on the App Registration, such as User.Read.All.

You would instead read the "oid" from the AAD access token passed from frontend to backend for discovering the user for formatting requests to Graph. Microsoft created a tutorial on implementing which you may find helpful.

Related