This post outlines how to limit access to an Azure Functions App so that only tenant users can access it, and how to then consume this function from an SPFx app in SharePoint.
Preparations
- Your functions should use AuthorizationLevel.Anonymous since the underlying App Service will be taking care of authentication.
- Enable CORS on the Function App in Azure and allow the SharePoint domain.
- On the App Registrations blade in Azure Entra ID, find SharePoint Online Client Extensibility Web Application Principal and copy the “Application (Client) ID”.
Secure the Functions App in Azure
- On the Authentication blade, select Add Identity Provider.
- Choose Microsoft.
- Under Client application requirement, select Allow requests from specific client applications and add the Client ID for the SharePoint app you copied above.
- Other settings can be left pretty much as is.
- When you click Add a new Entra ID App is created.
- Copy the App (Client) ID and App Display Name of the app.
Optional: Azure created some settings that we will not use. These can be removed to avoid confusion:
- On the Environment settings blade in the Function App, remove the MICROSOFT_PROVIDER_AUTHENTICATION_SECRET entry.
- In Entra ID, go to App Registrations and find the newly created app. On the Authentication blade, remove the “Web” platform. On the Certificates & Secrets blade, remove the “Client Secret”.
Setup SPFx Permissions
- Open package-solution.json in your SPFx solution. Add the following to the solution section:
1 2 3 4 5 6 7 8 9 10 |
"webApiPermissionRequests": [ { "resource": "Windows Azure Active Directory", "scope": "User.Read" }, { "resource": "[DISPLAY NAME OF THE ENTRA ID APP]", "scope": "user_impersonation" } ] |
- Build your solution ( gulp clean && gulp bundle --ship && gulp package-solution --ship ). A SharePoint package (.sppkg) file is created in the SharePoint/solution folder.
- Open your tenant app catalog and upload and upload the package. Enable it when asked.
- When done, click Go to API access page. Find your app and Approve it.
Note: At this point you can remove your app from the app catalog while you continue developing it locally.
Call the function
Finally, to call the function from your SPFx code, use AadHttpClient :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import { AadHttpClient, HttpClientResponse } from '@microsoft/sp-http'; ... this.context.aadHttpClientFactory .getClient('api://[CLIENT ID OF YOUR ENTRA ID APP]') .then((client: AadHttpClient): void => { client.get('https://[FUNCION-APP-NAME].azurewebsites.net/api/[FUNCTION NAME]', AadHttpClient.configurations.v1) .then((response: HttpClientResponse): Promise<any> => { return response.json(); }) .then((result: any): void => { console.log("✅", result); }, (err: any): void => { console.log("❌", err) }); }); |
Learnings
The normal authentication flow is to redirect the user to a login prompt. If each SPFx web parts used this flow it would not be a good user experience. Instead, SharePoint has a special app, the “SharePoint Online Client Extensibility Web Application Principal”. This app is pre-authenticated and we can use it to make secure. So when implementing authentication in our own APIs we need to allow the SharePoint app instead of our own.