Search code examples
vue.jsazure-active-directoryvue-authenticate

Azure AD with Vue Authenticate


I'm trying to configure vue-authenticate oauth2 for Microsoft Entra authentication, but I get the error:

Message: AADSTS9002325: Proof Key for Code Exchange is required for cross-origin authorization code redemption.

Solution

  • Found a workaround by changing response_type to be token instead of code.

    oauthType: '2.0',
    responseType: 'token',
    responseParams: {
      code: 'code',
    

    But that is returning the access_token, which is needed to call Graph API, not the id_token that is better suited for the authentication and authorization of your own API. See also Azure Authentication - Access Token returning wrong AUD(00000003-0000-0000-c000-000000000000)

    This library uses explicit flow by default which returns code first, and then you need to do exchange for token using your own server implementation. This is more secure process.

    Microsoft support

    I've also received support from Microsoft regarding this issue. During the test with the correlation ID, I verified with them that the above solution is equivalent to transitioning from Single Page Application (SPA) to Web Platform, and indeed, from the Authorization Code Flow to the Implicit Grant Flow. I'm noting this here as further confirmation of this answer.

    my suggestion

    The solution I'd suggest is Microsoft MSAL library with a code snippet like below

    const { result, acquireToken } = useMsalAuthentication(InteractionType.Popup, loginRequest);
    
    const state = reactive({
        resolved: false,
        data: {
      }
    });
    
    async function getAPIData() {
      var token = "";
        if (result.value) {
            try {
          token = result.value.idToken
          fetchDataWithToken(token)
            .then(data => {
              // implement your Vue's declarative rendering model
              // e.g your ref datamodels ... 
              data.message.datamodels.forEach((datamodel, index) => {
    

    Finally, considering my comment under the accepted answer, namely the fact that

    usually it is intended that calling a resource API is subject to an authorization flow

    you can easily replace the accessToken instead of the idToken

    token = result.value.accessToken
    

    once you have defined the api scope and

    export const loginRequest = {
      scopes: ['api:/your-web-api-app-ID-URI/yourResource.yourOperation'],
    };
    

    Finally, in the backend API, the scope (typically defined as Resource.Operation or often user_impersonation, without the app URI) will appear as scp when validating the accessToken, also known as the "user token". This information is highlighted in the Note from the Claims tab of https://jwt.ms/:

    The set of scopes exposed by your application for which the client application has requested (and received) consent. Your app should verify that these scopes are valid ones exposed by your app, and make authorization decisions based on the value of these scopes. Only included for user tokens.

    For the validation in a Python API, see this answer.

    TL;DR id vs access tokens

    My point is that access tokens, also said user tokens, are related to a consent for the api scope, which is typical of something like graph api, that requires the users to authorize the app to see their user profiles. That is very different from app roles, that can belong to the id tokens, as I initially said, and are typical of resource operations, for which a consent is not needed. In that scenario users have privileges to perform some app operations, for which it makes no sense to ask them a "consent".