reactjsazureauthenticationazure-ad-msalazure-service-principal

AuthenticationFailed while calling azure api


I am using an react app to call azure apis. This is how it is setup:

import { BrowserAuthError, PublicClientApplication } from '@azure/msal-browser';
import { MsalProvider, useMsal, AuthenticatedTemplate, UnauthenticatedTemplate } from '@azure/msal-react';
import { msalConfig } from './authConfig';

const pca = new PublicClientApplication(msalConfig);
const { instance, accounts } = useMsal();
const loginRequest = {
    scopes: ["User.Read"],
};

const response = await instance.acquireTokenPopup(loginRequest);
const accessToken = response.accessToken;
const fetchResponse = await fetch('https://management.azure.com/subscriptions/<subid>/resourceGroups/<rg>/providers/Microsoft.Network/frontDoors/<afd>?api-version=2021-06-01', {
headers: {
    Authorization: `Bearer ${accessToken}`,
},
});
const data = await fetchResponse.json();

This is what I have in authConfig

const msalConfig = {
auth: {
    clientId: <clientId>,
    authority: `https://login.microsoftonline.com/<tenantId>`,
    redirectUri: window.location.origin,
},
cache: {
    cacheLocation: "sessionStorage",
    storeAuthStateInCookie: false,
},
};

I have configured the following permissions in the app and I also created a service principal and gave it contributor access to the subscription. I am able to get the token using this code but using that token is resulting in

{
"error": {
    "code": "AuthenticationFailed",
    "message": "Authentication failed."
}
} 

Am I missing any step here?

permissions

On adding the azure service management API permissions, I am being asked for admin approval.

enter image description here

enter image description here

This is the enterprise applications settings:

enter image description here

enter image description here

enter image description here


Solution

  • Initially I created a Microsoft Entra ID application and added API permissions like below:

    enter image description here

    I added contributor role to Service Principal as you:

    enter image description here

    When I tried to access the API, I got the similar error as you:

    enter image description here

    enter image description here

    The error usually occurs if the required API permissions are not granted to the Microsoft Entra ID application.

    To resolve the error, you need to add Azure Service Management delegated API permission like below:

    enter image description here

    And in the code pass scope as https://management.azure.com/user_impersonation like

    scopes: ["https://management.azure.com/user_impersonation"]
    

    I am able to fetch the API results successfully as below:

    
    const pca = new PublicClientApplication(msalConfig);
    
    function FetchDataComponent() {
        const { instance, accounts } = useMsal();
        const [data, setData] = useState(null);
        const [error, setError] = useState(null);
    
        const loginRequest = {
            scopes: ["https://management.azure.com/user_impersonation"],
        };
    
        const fetchData = async () => {
            try {
                const response = await instance.acquireTokenPopup(loginRequest);
                const accessToken = response.accessToken;
                const fetchResponse = await fetch('https://management.azure.com/subscriptions/xxx/resourceGroups/ruk/providers/Microsoft.Network/frontDoors?api-version=2019-05-01', {
                    headers: {
                        Authorization: `Bearer ${accessToken}`,
                    },
                });
    
                if (!fetchResponse.ok) {
                    throw new Error(`HTTP error! status: ${fetchResponse.status}`);
                }
    
                const data = await fetchResponse.json();
                setData(data);
            } catch (err) {
                setError(err.message);
            }
        };
    
        return (
            <div>
                <button onClick={fetchData}>Fetch Data</button>
                {error && <p>Error: {error}</p>}
                {data && <pre>{JSON.stringify(data, null, 2)}</pre>}
            </div>
        );
    }
    
    function App() {
        return (
            <MsalProvider instance={pca}>
                <AuthenticatedTemplate>
                    <FetchDataComponent />
                </AuthenticatedTemplate>
                <UnauthenticatedTemplate>
                    <p>Please sign in to see the data.</p>
                </UnauthenticatedTemplate>
            </MsalProvider>
        );
    }
    
    export default App;
    

    enter image description here

    enter image description here

    As I do not have any front door I got empty output:

    enter image description here