DouzeBri DouzeBra
DouzeBri DouzeBra

Reputation: 127

MS Graph API issue with React

I'm working on a React project.

I'm able to sign in in the graph API, also able to get the user's contacts, but, not able to get his calendar events.

the config file:

export const msalConfig = {
  auth: {
    clientId: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    authority: "https://login.microsoftonline.com/common",
    redirectUri: "http://localhost:4200",
  },
  cache: {
    cacheLocation: "sessionStorage", // This configures where your cache will be stored
    storeAuthStateInCookie: true, // Set this to "true" if you are having issues on IE11 or Edge
  }
};

// Add scopes here for ID token to be used at Microsoft identity platform endpoints.
export const loginRequest = {
 scopes: ["Calendars.ReadWrite", "Contacts.Read"]
};

// Add the endpoints here for Microsoft Graph API services you'd like to use.
export const graphConfig = {
  graphMeEndpoint: "https://graph.microsoft.com/v1.0/me",
  graphCalendarsEndpoint: "https://graph.microsoft.com/v1.0/me/events",
  graphContactsEndpoint: "https://graph.microsoft.com/v1.0/me/contacts",
};

1/ The working part

the importContact.jsx file:

...
import { loginRequest, graphConfig } from '../authConfig.jsx';
import { useMsal } from "@azure/msal-react";

const ImportContacts = (props) => {
    const { instance, accounts, inProgress } = useMsal();
    const [accessToken, setAccessToken] = useState(null);
    const [graphData, setGraphData] = useState(null);

    const getMicrosoftContacts = () => {
    const request = {
        ...loginRequest,
        account: accounts[0]
    };
    var contacts= [];

  // Silently acquires an access token which is then attached to a request for Microsoft Graph data
  instance.acquireTokenSilent(request).then((response) => {
    console.log('acquireTokenSilent')
      setAccessToken(response.accessToken);
      callMsGraph(response.accessToken).then(
        response => {
          setGraphData(response);
          console.log(response)
          for (const item of response.value){
            contacts.push({
                provider: 'Microsoft',
                id: item.id,
                email: item.emailAddresses[0].address,
                firstName: item.givenName,
                lastName: item.surname,
                name: item.displayName,
                label:item.displayName + " (" + item.emailAddresses[0].address + ")" }
              )
          }
          setItems(contacts);
        }
        );
  }).catch((e) => {
      instance.acquireTokenPopup(request).then((response) => {
          setAccessToken(response.accessToken);
          callMsGraph(response.accessToken).then(
            response => {
              setGraphData(response);
              for (const item of response.value){
                contacts.push({
                    provider: 'Microsoft',
                    id: item.id,
                    email: item.emailAddresses[0].address,
                    firstName: item.givenName,
                    lastName: item.surname,
                    name: item.displayName,
                    label:item.displayName }
                  )
              }
              setItems(contacts);
            }
            );
          });
      });
    }

    async function callMsGraph(accessToken) {
    const headers = new Headers();
    const bearer = `Bearer ${accessToken}`;

    headers.append("Authorization", bearer);

    const options = {
        method: "GET",
        headers: headers
    };

    return fetch(graphConfig.graphContactsEndpoint, options)
        .then(response => response.json())
        .catch(error => console.log(error));
    }
    ...
}

2/ The non working part in events.jsx file:

...
import { loginRequest, graphConfig } from '../authConfig.jsx';
import { useMsal } from "@azure/msal-react";

class Events extends Component {

    constructor(props) {
        super(props);
        this.getMicrosoftEvents = this.getMicrosoftEvents.bind(this);
    }

    componentDidMount(){
        var date = new Date();
        var firstDay = new Date(date.getFullYear(), date.getMonth(), 1);
        var lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);
        this.getMicrosoftEvents(firstDay, lastDay);
    }

    getMicrosoftEvents(start, end) {
        console.log('log displayed in console')

        const { instance, accounts, inProgress } = useMsal();
        const [accessToken, setAccessToken] = useState(null);
        const [graphData, setGraphData] = useState(null);
    
        console.log('log not displayed in console')

        const request = {
            ...loginRequest,
            account: accounts[0]
        };

        // Silently acquires an access token which is then attached to a request for Microsoft Graph data
        instance.acquireTokenSilent(request).then((response) => {
            console.log('acquireTokenSilent')
            setAccessToken(response.accessToken);
            callMsGraph(response.accessToken, start, end).then(
            response => {
                console.log('microsoft response ' + response)
            }
            );
        }).catch((e) => {
            console.log('microsoft response error ' + e)
            instance.acquireTokenPopup(request).then((response) => {
                setAccessToken(response.accessToken);
                callMsGraph(response.accessToken, start, end).then(
                response => {
                    console.log('microsoft response ' + response)
                }
                );
            });
        });

        async function callMsGraph(accessToken, start, end) {
            console.log('callMsGraph ')
        const headers = new Headers();
        const bearer = `Bearer ${accessToken}`;
        
        headers.append("Authorization", bearer);
        console.log('Authorization ' + bearer)
    
        const options = {
            method: "GET",
            headers: headers
        };
    
        return fetch(graphConfig.graphCalendarsEndpoint 
           + '?startDateTime=' 
           + start 
           + '&endDateTime=' 
           + end,
           options)
            .then(response => {
                console.log('microsoft response ' + response.json())
                response.json();
            })
            .catch(error => console.log(error));
        }
    }

I'm not getting any error, the api call is not made, the difference between the two calls is one is made after a button click, and the other on load.

Adding logs showed me that the problem could be in this line as the logs are not displayed after it:

const { instance, accounts, inProgress } = useMsal();

What am I doing wrong?

Upvotes: 0

Views: 1375

Answers (1)

Danstan
Danstan

Reputation: 1771

In events.jsx Events component is a class component and you are calling useMsal() and useState() hooks in getMicrosoftEvents. That will not work because hooks can only be called in function components.

You need to make Events component functional like ImportContacts.

Instead of

class Events extends Component {
...

Do this

const Events= (props) => {
    const { instance, accounts, inProgress } = useMsal();
    const [accessToken, setAccessToken] = useState(null);
    const [graphData, setGraphData] = useState(null);
...

Upvotes: 1

Related Questions