azureoauthspfx

SPFX Azure AD-secured API


I have an asp.net api that is secured by Azure AD, hosted locally on an iis server. Configuring scalar with oauth is working fine. The scope of the azure App is:

api://4e3c3206-2f13-4c12-ae7b-92c4dc195b68/access

I now want to use this secured API with a custom SPFX solution following this example by Microsoft: Connect to Azure AD-secured APIs in SharePoint Framework solutions

package-solution.json

 "webApiPermissionRequests": [
    {
      "resource": "SharePoint App", //Display name of the azure app
      "scope": "access"
    }
  ]

Code getting the api data:

props.context.aadHttpClientFactory
.getClient('https://sharepoint-api:4444')
.then((client: AadHttpClient): void => {
  client
  .get('https://sharepoint-api:4444/data', AadHttpClient.configurations.v1)
  .then((response: HttpClientResponse): Promise<any> => {
    return response.json();
  })
  .then((data: any): void => {
        console.log(data);
  })
});

Whatever I insert into the getClient() I get an error 500 as response:

<m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
  <m:code>-1, System.AggregateException</m:code>
  <m:message xml:lang="de-DE">One or more errors occurred.</m:message>
</m:error>

If I use the same code with graph api it is working without any problems:

props.context.aadHttpClientFactory
.getClient('https://graph.microsoft.com')
.then((client: AadHttpClient): void => {
  client
  .get('https://graph.microsoft.com/v1.0/me', AadHttpClient.configurations.v1)
  .then((response: HttpClientResponse): Promise<any> => {
    return response.json();
  })
  .then((data: any): void => {
        console.log(data);
  })
});

What do I need to change to make the custom api working?


Solution

  • Have you granted your web part SPO admin consent from M365 SharePoint Admin Center --> API Access. Graph will work with any older Admin consent, however for any new App registration Admin needs to grant consent for it to work. Below is a sample function which I have used for a similar use case

    public async getDataPOSTMethod(Url: string,webpartContext:WebPartContext, ClinetID:string) {
    
            const myHeaders = new Headers();
            myHeaders.append("Content-Type", "application/json");
            myHeaders.append("Accept", "application/json");
    
            const requestOptions = {
                method: "POST",
                headers: myHeaders,
            };
    
            const data = await webpartContext.aadHttpClientFactory
            .getClient(ClinetID)
            .then((client: AadHttpClient) => {
              return client
                .fetch(
                    Url,
                  AadHttpClient.configurations.v1,  
                  requestOptions
                )
              });
            return await data.json();
        }