I have created a electron app and need to integrate O365 login in it,every blog or video I see everyone is referring to redirect URI as http://localhost but to me it seems a concern using this in production as any malicious app running in desktop can fetch the token from this endpoint in between
authconfig.js
const { PublicClientApplication, InteractionRequiredAuthError } = require('@azure/msal-node');
const { NativeBrokerPlugin } = require("@azure/msal-node-extensions");
const { shell} = require('electron');
const {promises} = require('fs');
class AuthProvider {
msalConfig
clientApplication;
account;
cache;
tokenResponseFromCache;
constructor(msalConfig) {
this.msalConfig = {
auth:{
clientId:"84XXXXXXXXXXXXXXX",
authority:"https://login.microsoftonline.com/876XXXXXXXXXXXXXX/",
},
broker: { nativeBrokerPlugin: new NativeBrokerPlugin() },
system:{
loggerOpitons:{
loggerCallback(logLevel,message,containspii){
},
piiLoggingEnabled:false,
logLevel:3,
}
}
};
/**
* Initialize a public client application.
*/
this.msalConfig = msalConfig;
this.clientApplication = new PublicClientApplication(this.msalConfig);
this.cache = this.clientApplication.getTokenCache();
this.account = null;
}
async login() {
try{
const openBrowser = async(url)=>{
await shell.openExternal(url);
};
const successTemplate = await promises.readFile("./redirect.html","utf-8");
const authResponse = await this.clientApplication.acquireTokenInteractive({
openBrowser,
successTemplate:successTemplate,
failureTemplate:"<h1>Oops!Something went Wrong</h1><p>Close the window and try again</p>",
});
console.log(authResponse);
this.account = authResponse.account;
}catch(error){
console.log(error);
}
}
async logout() {
if (!this.account) return;
try {
/**
* If you would like to end the session with AAD, use the logout endpoint. You'll need to enable
* the optional token claim 'login_hint' for this to work as expected.
*/
if (this.account.idTokenClaims.hasOwnProperty('login_hint')) {
await shell.openExternal(`${this.msalConfig.auth.authority}/oauth2/v2.0/logout?logout_hint=${encodeURIComponent(this.account.idTokenClaims.login_hint)}`);
}
await this.cache.removeAccount(this.account);
this.account = null;
} catch (error) {
console.log(error);
}
}
async getToken(tokenRequest) {
let authResponse;
const account = this.account || (await this.getAccount());
if(this.tokenResponseFromCache){
authResponse = this.tokenResponseFromCache;
}
else{
if (account) {
tokenRequest.account = account;
authResponse = await this.getTokenSilent(tokenRequest);
} else {
authResponse = await this.getTokenInteractive(tokenRequest);
}
}
return authResponse || null;
}
async getTokenSilent(tokenRequest) {
try {
return await this.clientApplication.acquireTokenSilent(tokenRequest);
} catch (error) {
if (error instanceof InteractionRequiredAuthError) {
console.log('Silent token acquisition failed, acquiring token interactive');
return await this.getTokenInteractive(tokenRequest);
}
}
}
async getTokenInteractive(tokenRequest) {
try {
const openBrowser = async (url) => {
await shell.openExternal(url);
};
const authResponse = await this.clientApplication.acquireTokenInteractive({
...tokenRequest,
openBrowser,
successTemplate: '<h1>Successfully signed in!</h1> <p>You can close this window now.</p>',
errorTemplate: '<h1>Oops! Something went wrong</h1> <p>Check the console for more information.</p>',
});
return authResponse;
} catch (error) {
throw error;
}
}
/**
* Handles the response from a popup or redirect. If response is null, will check if we have any accounts and attempt to sign in.
* @param response
*/
async handleResponse(response) {
if (response !== null) {
this.account = response.account;
} else {
this.account = await this.getAccount();
}
return this.account;
}
/**
* Calls getAllAccounts and determines the correct account to sign into, currently defaults to first account found in cache.
*/
async getAccount() {
const currentAccounts = await this.cache.getAllAccounts();
if (!currentAccounts) {
console.log('No accounts detected');
return null;
}
if (currentAccounts.length > 1) {
// Add choose account code here
console.log('Multiple accounts detected, need to add choose account code.');
return currentAccounts[0];
} else if (currentAccounts.length === 1) {
return currentAccounts[0];
} else {
return null;
}
}
}
module.exports = AuthProvider;
in the above code I tried passing redirect URI like-
`this.msalConfig = {
auth:{
clientId:"841XXXXXXX",
authority:"https://login.microsoftonline.com/875XXXXXXXXXXXXXX/",
redirectUri : "http://localhost/authcallback" (also tried "https://appname/authcallback"
}
}`
and registered the tried URL in Azure app as well
but this doesn't work by default still http://localhost is only getting passed with the request as redirect URI so when I login I get this error
[]
if anyone could guide me on what wrong am I doing here or is my understanding wrong, it would be really helpful, I referred to all other posts on stack overflow but nothing worked for me yet.
Thanks in advance