最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Azure AD App Redirect URI for Chrome Extension - Stack Overflow

programmeradmin3浏览0评论

I'm using the Microsoft Authentication Library for JavaScript (MSAL.js) version 1.3.2 in my chrome extension built on React JS. I have two login scenario I need to support in order to get a bearer token used in the rest of my application:

  1. promptLogin() handles the first time the user authenticates in my extension.
  2. getTokenAsync() handles acquiring a bearer token silently for a user who has already authenticated in my extension. This approach returns an id token that I do not use, should I? Instead in my source code at the bottom of the post you'll see I call promptLogin() right after this to get the bearer token.

Both of these methods are called within the main login() method based if the user is authenticated or not. From the MSAL.js docs it seems like redirectUri is optional and authentication for my two scenarios works as expected in development environment on localhost without this property.

This property redirectUri seems to be required in production when the user interacts with the extension via Chrome or the new Microsoft Edge. I am not sure what the redirectUri would be in this case or if I even need one. I belive it should be formatted as /.

The flow I expect is when the the user clicks "LOG IN" for the first time my promptLogin() handles their request.

I log in with my account

Then get this error

Here's my app registration and the redirect URIs in Azure AD. "Supported Account types are: Accounts in any organizational directory (Any Azure AD directory - Multitenant)". I have also checked both "Access tokens" and "ID tokens" for the "To enable the implicit grant flow, select the tokens you would like to be issued by the authorization endpoint:".

This is my MSAL configuration.

this.msalConfig = {
    auth: {
        clientId: process.env.REACT_APP_MICROSOFT_GRAPH_CLIENT_ID,
        redirectUri: ".html"
    },
};

this.msalInstance = new Msal.UserAgentApplication(this.msalConfig);
this.scopes = [
    "directory.accessasuser.all", 
    "directory.readwrite.all", 
    "user.readwrite.all"
];

The main login method.

async login() {       
    if (this.msalInstance.getAccount()) {
        alert('authenticated');         
        const token = await this.getTokenAsync();
        return token;
        
    } else {
        alert('not authenticated please sign in');
        await this.promptLogin();
        const token = await this.getTokenAsync();
        return token;
    }        
}

Logic for my 2 scenarios based on if the user is authenticated or not.

getTokenAsync() {
    return new Promise((resolve, reject) => {
        let tokenRequest = {
            scopes: this.scopes
        };
        this.msalInstance.acquireTokenSilent(tokenRequest)
        .then(response => {
            resolve(response.accessToken);
        })
        .catch(err => {
            console.error(`E: ${err}`);                
            if (err.name === "InteractionRequiredAuthError") {
                return this.msalInstance.acquireTokenPopup(tokenRequest)
                    .then(response => {
                        resolve(response.accessToken);
                    })
                    .catch(err => {
                        console.error(`E: ${err}`);
                        reject();
                    });
            }
        });
    });
}
promptLogin() {
    return new Promise((resolve, reject) => {
        let loginRequest = {
            scopes: this.scopes
        };          
        this.msalInstance.loginPopup(loginRequest)
        .then(response => {
            console.log(`res: ${JSON.stringify(response)}`);
            resolve();
        })
        .catch(err => {
            alert(`E: ${err}`);
            console.error(`E: ${err}`);
            reject();
        });
    });
}

I'm using the Microsoft Authentication Library for JavaScript (MSAL.js) version 1.3.2 in my chrome extension built on React JS. I have two login scenario I need to support in order to get a bearer token used in the rest of my application:

  1. promptLogin() handles the first time the user authenticates in my extension.
  2. getTokenAsync() handles acquiring a bearer token silently for a user who has already authenticated in my extension. This approach returns an id token that I do not use, should I? Instead in my source code at the bottom of the post you'll see I call promptLogin() right after this to get the bearer token.

Both of these methods are called within the main login() method based if the user is authenticated or not. From the MSAL.js docs it seems like redirectUri is optional and authentication for my two scenarios works as expected in development environment on localhost without this property.

This property redirectUri seems to be required in production when the user interacts with the extension via Chrome or the new Microsoft Edge. I am not sure what the redirectUri would be in this case or if I even need one. I belive it should be formatted as https://ihmmiapcpnfpphpdinbmjfglladedjoa.chromiumapp/.

The flow I expect is when the the user clicks "LOG IN" for the first time my promptLogin() handles their request.

I log in with my account

Then get this error

Here's my app registration and the redirect URIs in Azure AD. "Supported Account types are: Accounts in any organizational directory (Any Azure AD directory - Multitenant)". I have also checked both "Access tokens" and "ID tokens" for the "To enable the implicit grant flow, select the tokens you would like to be issued by the authorization endpoint:".

This is my MSAL configuration.

this.msalConfig = {
    auth: {
        clientId: process.env.REACT_APP_MICROSOFT_GRAPH_CLIENT_ID,
        redirectUri: "https://ihmmiapcpnfpphpdinbmjfglladedjoa.chromiumapp/popup.html"
    },
};

this.msalInstance = new Msal.UserAgentApplication(this.msalConfig);
this.scopes = [
    "directory.accessasuser.all", 
    "directory.readwrite.all", 
    "user.readwrite.all"
];

The main login method.

async login() {       
    if (this.msalInstance.getAccount()) {
        alert('authenticated');         
        const token = await this.getTokenAsync();
        return token;
        
    } else {
        alert('not authenticated please sign in');
        await this.promptLogin();
        const token = await this.getTokenAsync();
        return token;
    }        
}

Logic for my 2 scenarios based on if the user is authenticated or not.

getTokenAsync() {
    return new Promise((resolve, reject) => {
        let tokenRequest = {
            scopes: this.scopes
        };
        this.msalInstance.acquireTokenSilent(tokenRequest)
        .then(response => {
            resolve(response.accessToken);
        })
        .catch(err => {
            console.error(`E: ${err}`);                
            if (err.name === "InteractionRequiredAuthError") {
                return this.msalInstance.acquireTokenPopup(tokenRequest)
                    .then(response => {
                        resolve(response.accessToken);
                    })
                    .catch(err => {
                        console.error(`E: ${err}`);
                        reject();
                    });
            }
        });
    });
}
promptLogin() {
    return new Promise((resolve, reject) => {
        let loginRequest = {
            scopes: this.scopes
        };          
        this.msalInstance.loginPopup(loginRequest)
        .then(response => {
            console.log(`res: ${JSON.stringify(response)}`);
            resolve();
        })
        .catch(err => {
            alert(`E: ${err}`);
            console.error(`E: ${err}`);
            reject();
        });
    });
}
Share Improve this question edited May 4, 2021 at 15:02 yglodt 14.6k15 gold badges101 silver badges136 bronze badges asked Jun 15, 2020 at 20:25 greggreg 1,2142 gold badges24 silver badges52 bronze badges 1
  • 2 Hi Greg, I have a similar setup and am having difficulties getting it to work. Did you figure out this? – Rinor Commented Jul 18, 2020 at 11:10
Add a ment  | 

2 Answers 2

Reset to default 4

The protocol for chromium extensions is chrome-extension://, so I believe your redirect uri should be: chrome-extension://ihmmiapcpnfpphpdinbmjfglladedjoa/popup.html

Edit: In addition to using the above redirect URI format, you need to ensure the following:

  1. The redirect URI is added to your application's redirect URIs in the Azure Portal (under "Mobile and desktop applications").
  2. The page used for the redirect URI is included in the web_accessible_resources section of your extension's manifest.json.

I got this to work by just simply using the Chrome Identity API as shown below:

var redirectUrl = chrome.identity.getRedirectURL()

/*global chrome*/
chrome.identity.launchWebAuthFlow(
  {
    url: 'https://login.microsoftonline./<tenant id or just 'mon'>/oauth2/v2.0/authorize?' +
      'response_type=token' +
      '&response_mode=fragment' +
      `&client_id=Azure AD Application Client ID` +
      `&redirect_uri=${redirectUrl}` +
      '&scope=openid https://management.azure./user_impersonation profile',
    interactive: true
  },
  function (responseWithToken) {
      // the access token needs to be extracted from the response.
  }
);

Additionally, you need to add Identity to permissions in the manifest.js, which is well documented here: https://developer.chrome./apps/app_identity

发布评论

评论列表(0)

  1. 暂无评论