Call Azure function secred by AAD from SPFX Webpart

Jakub Husařík 0 Reputation points
2024-10-16T11:40:32.8633333+00:00

Hello,

i am trying to call Azure Function secured by AD from sharepoint webpart. But still getting 401 Unauthorized. Can please anybody point me right direction, i trying many tutorials official and unofficials and nothing works correctly. Thanks for any advice.

Here is steps i made:

  1. Create default azure function in local. Azure function is anonymous and return just string "Hello world".
  2. Create azure function in Azure portal and upload azure function from local to cloud.
  3. Test azure function using browser/Powershell(Invoke-WebRequest) - works fine, return string "Hello World"
  4. Add identity and Authorization to Azure Function:
    1. Identity provider: Microsoft
    2. create new app registration with name : AuthenticationFunctionAppAZF
    3. Client secret setting name = MICROSOFT_PROVIDER_AUTHENTICATION_SECRET
    4. Issuer_URL= https://login.microsoftonline.com/common/v2.0
    5. Allowed token audiences: 8bdb826f-bbbc-4f6b-923a-63777a5c3550(Client ID of registration)
    6. Client application requirement: Allow Requst only from app. itself
    7. Identity requirement: Allow request form any identity
    8. Tenant Requirement: Allow request from specific tenant, allowed tenant is ID of my tenant
  5. In App registration(AuthenticationFunctionAppAZF) of my Azure Function(AuthenticationFunctionAppAZF) In authentication i put:
  6. In single-page application:
    1. https://oauth.pstmn.io/v1/browser-callback - for testing using postman
    2. https://authenticationfunctionappazf.azurewebsites.net/.auth/login/aad/callback
  7. Allowed Tokens
  8. Allowed ID Tokens
  9. Set Supported account types: unts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant)
  10. In api premission see image User's image
  11. In Expose API:
    1. change Application ID URI: to https://tenantname.onmicrosoft.com/ClientID_of_AzureAppRegistration_of_My_Function
    2. Add scopes:
      1. user_impersonation
      2. access_as_user
  12. When i testing using browser and go to this page : https://authenticationfunctionappazf.azurewebsites.net/.auth/login/aad/callback then i log in to azure portal, then i try call my function url using url: https://authenticationfunctionappazf.azurewebsites.net/api/AuthenticationFunctionAppAZF? I get correct response: "Hello world!"
  13. Then i create my spfx webpart using yo generator, here is my code which call azure function using aadhttpclient:
       import * as React from 'react';
       import { useState } from 'react';
       import { AadHttpClient, IHttpClientOptions, HttpClientResponse } from '@microsoft/sp-http';
       import { WebPartContext } from '@microsoft/sp-webpart-base';
       export interface IHelloUserProps {
               context: WebPartContext;
       }
       export interface IHelloWorld {
               hello: string;
       }
       const HelloUser: React.FC<IHelloUserProps> = ({ context }) => {
               const [hello, setHello] = useState<IHelloWorld | null>(null);
               const fetchUserData = () => {
                       console.log('Fetching user data...');
                       if (!context) {
                               console.error('Context is undefined');
                               return;
                       }
                       console.log('Context:', context);
                       if (!context.aadHttpClientFactory) {
                               console.error('aadHttpClientFactory is undefined');
                               return;
                       }
                       console.log('aadHttpClientFactory:', context.aadHttpClientFactory);
                       const options: IHttpClientOptions = {
                               headers: {
                                       'Accept': 'application/json;odata.metadata=none'
                               }
                       };
                       context.aadHttpClientFactory
                               .getClient('https://artetechnology.onmicrosoft.com/8bdb826f-bbbc-4f6b-923a-63777a5c3550')
                               .then((client: AadHttpClient): void => {
                                       console.log('AadHttpClient obtained:', client);
                                       client
                                               .get('https://authenticationfunctionappazf.azurewebsites.net/api/AuthenticationFunctionAppAZF?', AadHttpClient.configurations.v1, options)
                                               .then((response: HttpClientResponse): Promise<any> => {
                                                       console.log('Response received:', response);
                                                       return response.json();
                                               })
                                               .then((user: any): void => {
                                                       console.log('User data:', user);
                                                       setHello(user);
                                               })
                                               .catch((error: any): void => {
                                                       console.error('Error parsing response:', error);
                                               });
                               })
                               .catch((error: any): void => {
                                       console.error('Error getting AadHttpClient:', error);
                               });
               };
               return (
                       <div>
                               <button onClick={fetchUserData}>Fetch User Data</button>
                               {hello ? <div>Hello, {hello.hello}</div> : <div>Loading...</div>}
                       </div>
               );
       };
       export default HelloUser;
       
       
    
    After i try to call start my local workbench a try to call my azure function i get error User's image
  14. Same issues is when i : gulp bundle --ship, gulp package-solution --ship, then upload solution to sharepoint, allow premission, and add webpart to any site and try fetch the azure funciton.
  15. I added premission to package-solution.json :
       {
         "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
         "solution": {
           "name": "spfx-api-scopes-tutorial-client-side-solution",
           "id": "b0765ed9-4954-444b-94d9-168ac6a55711",
           "version": "1.0.0.0",
           "includeClientSideAssets": true,
           "skipFeatureDeployment": true,
           "isDomainIsolated": true,
           "webApiPermissionRequests": [
             {
               "resource": "Microsoft Graph",
               "scope": "User.ReadBasic.All"
             },
             {
               "resource": "FakturyAppGetAzVaultSecrets",
               "scope": "user_impersonation"
             }
           ],
           "developer": {
             "name": "",
             "websiteUrl": "",
             "privacyUrl": "",
             "termsOfUseUrl": "",
             "mpnId": "Undefined-1.20.0"
           },
           "metadata": {
             "shortDescription": {
               "default": "spfx-api-scopes-tutorial description"
             },
             "longDescription": {
               "default": "spfx-api-scopes-tutorial description"
             },
             "screenshotPaths": [],
             "videoUrl": "",
             "categories": []
           },
           "features": [
             {
               "title": "spfx-api-scopes-tutorial Feature",
               "description": "The feature that activates elements of the spfx-api-scopes-tutorial solution.",
               "id": "f22f448f-6058-46e5-a8ef-1f701d51b886",
               "version": "1.0.0.0"
             }
           ]
         },
         "paths": {
           "zippedPackage": "solution/spfx-api-scopes-tutorial.sppkg"
         }
       }
       
       
    
  16. User's image
Azure Functions
Azure Functions
An Azure service that provides an event-driven serverless compute platform.
5,911 questions
Microsoft 365 and Office | SharePoint | For business | Windows
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Pinaki Ghatak 5,600 Reputation points Microsoft Employee Volunteer Moderator
    2024-10-18T09:12:23.3+00:00

    Hello @Jakub Husařík

    One thing to check is whether the client ID you are using to obtain the AAD token is the same as the one you registered in the Azure Function app.

    Make sure that the client ID you are using in the getClient method matches the client ID of the Azure AD app registration you created for the Azure Function app.

    Another thing to check is whether the user account you are using to authenticate has the necessary permissions to call the Azure Function. Make sure that the user account you are using has been granted the necessary permissions to call the Azure Function app.

    If you have checked these things and are still encountering issues, you may want to try using Fiddler or another HTTP debugging tool to see the exact request and response being sent between your SPFX web part and the Azure Function app. This can help you identify any issues with the request or response that may be causing the 401 Unauthorized error.

    I hope this helps

    0 comments No comments

  2. Jakub Husařík 0 Reputation points
    2024-10-22T11:10:35.4433333+00:00

    I find out solution, in code for aadhttpclientFactory in .getClient must be ID of Azure Function registration and in authentication for Azure Function in Additional checks must be either: Allow requests from specific client applications(You must insert ClientID for SharePoint Online Client Extensibility Web Application Principal if you calling azure function from Sharepoint WebPart) or Allow requests from any application (Not recommended)

    Then it works even in local workbench.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.