I have an ASP.Net Core API as backend and React WebApp as client. The API and WebApp were deployed to Azure with separate App Services. I also registered two applications in Azure AD so I can use it in the Authentication settings for the App Services and other security settings. The API and WebApp will be used internally by the users of the company so one of the requirement is they need not to be prompted for login.
I'm still new in using Azure and React JS and I'm not really much of a front-end developer so I really need some advice. My issues/errors is when using MSAL.js. I followed instructions & samples from https://github.com/AzureAD/microsoft-authentication-library-for-js but I'm not really sure how to fix the errors and sometimes I'm getting a Server Error 502 when I ran the web app. Below are my codes.
authorize.jsx
const msalConfig = {
clientId: process.env.REACT_APP_AZ_CLIENT_ID,
secret: process.env.REACT_APP_AZ_CLIENT_SECRET,
authority: process.env.REACT_APP_AZ_OAUTH2_ENDPOINT_AUTH_URL,
token: process.env.REACT_APP_AZ_OAUTH2_ENDPOINT_TOKEN_URL,
redirect_uri: process.env.REACT_APP_REDIRECT_URI,
scopes:process.env.REACT_APP_AZ_SCOPE_WRITE
};
export default function AuthorizeLogin(accessToken) {
const headers = new Headers();
const bearer = `Bearer ${accessToken}`;
const contentType = "application/json";
console.log(`Bearer: ${bearer}`);
headers.append("Content-Type", contentType);
headers.append("Authorization", bearer);
const options = {
method: "POST",
headers: headers
};
return fetch(msalConfig.authority, options)
.then(response => response.json())
.catch(error => console.log(error));
}
App.js
import React, { useState, useEffect } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import FetchDatasets from './components/datasets/fetchhDatasets';
import FetchSampleDatasets from './components/charts/sampleDatasetChart';
import NotFound from './components/NotFound404';
/* MSAL configs */
import authorizeLogin from './components/authenticate/authorize';
import { loginRequest } from './components/authenticate/authConfig';
/* MSAL */
import { useMsal, useAccount, AuthenticatedTemplate, UnauthenticatedTemplate } from "@azure/msal-react";
/* React Context API */
import DataContextProvider from './context/dataContextProvider';
let currentAccounts = [];
function getAccounts(instance, account) {
if (account !== null || account !== undefined || account === 1) {
console.log(`account: ${account}`)
return;
}
else if (account === null || account === undefined) {
currentAccounts = instance.getallaccounts();
if (currentAccounts .length === 0) {
const loginresponse = instance.loginpopup({ scopes: loginrequest.scopes });
if (loginresponse) {
currentAccounts = loginresponse.account;
account = currentAccounts[0];
}
}
else {
account = currentAccounts[0];
}
console.log(`account: ${currentAccounts[0]}`);
}
else if (currentAccounts.length > 1) {
console.log(`multiple accounts detected: ${currentAccounts.length}`);
}
else if (currentAccounts.length === 1) {
account = currentAccounts[0];
}
}
export default function App() {
const { instance, inProgress, accounts } = useMsal();
const [apiData, setApiData] = useState(null);
const account = useAccount(accounts[0] || {});
useEffect(() => {
const getAccessToken = async () => {
try {
if(account && inProgress === "none") {
await instance.acquireTokenSilent({
scopes: loginRequest.scopes,
account: getAccounts(instance, account)
}).then((response) => {
console.log(`Response: ${response}`);
if(response) {
authorizeLogin(response.accessToken)
.then((result) => setApiData(result))
.catch((error => console.log(`Error: ${error}`)));
}
});
}
} catch(error) {
console.log('acquireTokenPopup() start');
return instance.acquireTokenPopup({
scopes: loginRequest.scopes,
account: getAccounts(instance, account)
})
.then((response) => {
authorizeLogin(response.accessToken)
.then((result) => setApiData(result))
.catch((error => console.log(`Error: ${error}`)));
});
}
}
getAccessToken();
}, [instance, account, inProgress]);
return(
<>
<div>
<AuthenticatedTemplate>
<span>There are currently {accounts.length} users signed in!</span>
</AuthenticatedTemplate>
<UnauthenticatedTemplate>
<span>There are no user signed in!</span>
</UnauthenticatedTemplate>
<DataContextProvider>
<Router>
<Switch>
<Route exact path="/" component={Dashboard} />
<Route path= "/datasets/fetchDatasets" exact component={FetchDatasets} />
<Route path= "/charts/sampleDatasetChart" exact component={FetchSampleDatasets} />
<Route component={NotFound} />
</Switch>
</Router>
</DataContextProvider>
</div>
</>
);
}
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { msalConfig } from './components/authenticate/authConfig';
import { MsalProvider } from '@azure/msal-react';
import * as msal from '@azure/msal-browser';
// MSAL configuration
const configMsal = {
auth: {
clientId: msalConfig.clientId,
secret: msalConfig.secret,
authority: msalConfig.authority,
token: msalConfig.token,
redirectUri: msalConfig.redirect_uri,
navigateToLoginRequestUrl: true
},
cache: {
cacheLocation: "sessionStorage",
storeAuthStateInCookie: false
}
};
const msalObj = new msal.PublicClientApplication(configMsal);
let currentAccounts = msalObj.getAllAccounts();
console.log(`CurrentAccounts count: ${currentAccounts.length}`);
const AppProvider = () => (
<MsalProvider instance = {msalObj}>
<App />
</MsalProvider>
);
ReactDOM.render(
<AppProvider />
,document.getElementById('root')
);
serviceWorker.unregister();
Questions
- What could be the reason I can't get a user from the Azure AD when using instance.getAllAccounts()?
- I'm confuse if I should use "acquireTokenPopup" or "acquireTokenRedirect"? Should I use "acquireTokenRedirect" because I created a Uri in the Authentication -> Redirect URI in the application I registered in the AAD?
- Did I do the right steps in acquiring tokens that I can use as Bearer?
- Is there additional code I need to add in the API?
I hope I make sense in my questions and explanations. Thanks in advance.