Azure AD with Vue Authenticate

307 Views Asked by At

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.
2

There are 2 best solutions below

2
On BEST ANSWER

From a security viewpoint it is recommended to use a library with PKCE support and to use response_type=code as you say.

Also you should send access tokens to your API, not ID tokens. You are currently getting the wrong type of access token and you need to expose your own API scope to fix it.

My blog posts explain how this should work:

0
On

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".