I am trying to embed PowerBI report in a react app. I have followed this example from microsoft. The example is in Typescript but I am using Javascript
Here is my index.js file.
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
import { AuthProvider } from "./context/AuthProvider";
import { CountryProvider } from "./context/CountryProvider";
import theme from "./theme";
import { ThemeProvider } from "@mui/material/styles";
import { Provider } from "react-redux";
import { store } from "./store/store";
import * as config from "./pages/powerbi/keys";
import { LogLevel, PublicClientApplication } from "@azure/msal-browser";
import { MsalProvider } from "@azure/msal-react";
// TRIED THIS TO FIX THE ISSUE
if (typeof window !== 'undefined' && !window.crypto) {
window.crypto = window.msCrypto;
}
const msalInstance = new PublicClientApplication({
auth: {
clientId: config.clientId,
authority: config.authorityUrl,
redirectUri: "http://{SERVER_IP_ADDRESS}/FOLDER_NAME/"
},
cache: {
cacheLocation: 'localStorage',
storeAuthStateInCookie: false,
},
system: {
loggerOptions: {
loggerCallback: (level, message, containsPii) => {
console.log(`LEVEL: ${level} MESSAGE: ${message}`);
},
piiLoggingEnabled: false,
logLevel: LogLevel.Verbose
},
cryptoOptions: {
usePkce: false // TRIED THIS TO FIX THE ISSUE
}
}
});
console.log("CRYPTO: ", window.crypto);
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<div id="MainDiv">
<Provider store={store}>
<BrowserRouter basename="Reactjs_Demo/">
<AuthProvider>
<CountryProvider>
<ThemeProvider theme={theme}>
<MsalProvider instance={msalInstance}>
<App />
</MsalProvider>
</ThemeProvider>
</CountryProvider>
</AuthProvider>
</BrowserRouter>
</Provider>
</div>
);
And this is the PowerBI component
import React, { useEffect, useRef, useState, useContext } from "react";
import { AuthenticationResult, InteractionType, EventType, AuthError } from "@azure/msal-browser";
import { MsalContext } from "@azure/msal-react";
import { service, factories, models } from "powerbi-client";
import * as config from "./keys";
const powerbi = new service.Service(factories.hpmFactory, factories.wpmpFactory, factories.routerFactory);
export default function PowerBiReport() {
const [accessToken, setAccessToken] = useState("");
const [embedUrl, setEmbedUrl] = useState("");
const [error, setError] = useState([]);
const reportRef = useRef(null);
const context = useContext(MsalContext);
const authenticate = () => {
const msalInstance = context.instance;
const msalAccounts = context.accounts;
const msalInProgress = context.inProgress;
const isAuthenticated = context.accounts.length > 0;
if (error.length > 0) {
return;
}
const eventCallback = msalInstance.addEventCallback((message) => {
if (message.eventType === EventType.LOGIN_SUCCESS && !accessToken) {
const payload = message.payload;
const name = payload.account?.name ? payload.account?.name : "";
setAccessToken(payload.accessToken);
setUsername(name);
tryRefreshUserPermissions();
}
});
const loginRequest = { scopes: config.scopeBase, account: msalAccounts[0] };
if (!isAuthenticated && msalInProgress === InteractionType.None) {
msalInstance.loginRedirect(loginRequest);
} else if (isAuthenticated && accessToken && !embedUrl) {
getEmbedUrl();
msalInstance.removeEventCallback(eventCallback);
} else if (isAuthenticated && !accessToken && !embedUrl && msalInProgress === InteractionType.None) {
setUsername(msalAccounts[0].name);
msalInstance.acquireTokenSilent(loginRequest).then((response) => {
setAccessToken(response.accessToken);
getEmbedUrl();
}).catch((error) => {
if (error.errorCode === "consent_required" || error.errorCode === "interaction_required" || error.errorCode === "login_required") {
msalInstance.acquireTokenRedirect(loginRequest);
} else if (error.errorCode === '429') {
setError(["Our Service Token Server (STS) is overloaded, please try again in sometime"]);
} else {
setError(["There was some problem fetching the access token" + error.toString()]);
}
});
}
};
const tryRefreshUserPermissions = () => {
fetch(config.powerBiApiUrl + "v1.0/myorg/RefreshUserPermissions", {
headers: { "Authorization": "Bearer " + accessToken },
method: "POST"
})
.then(response => {
if (response.ok) {
console.log("User permissions refreshed successfully.");
} else {
if (response.status === 429) {
console.error("Permissions refresh will be available in up to an hour.");
} else {
console.error(response);
}
}
})
.catch(error => {
console.error("Failure in making API call." + error);
});
};
const getEmbedUrl = () => {
fetch(config.powerBiApiUrl + "v1.0/myorg/groups/" + config.wspaceId + "/reports/" + config.reportId, {
headers: { "Authorization": "Bearer " + accessToken },
method: "GET"
})
.then(response => {
const errorMessage = ["Error occurred while fetching the embed URL of the report", "Request Id: " + response.headers.get("requestId")];
response.json()
.then(body => {
if (response.ok) {
setEmbedUrl(body["embedUrl"]);
} else {
errorMessage.push("Error " + response.status + ": " + body.error.code);
setError(errorMessage);
}
})
.catch(() => {
errorMessage.push("Error " + response.status + ": An error has occurred");
setError(errorMessage);
});
})
.catch(error => {
setError([error]);
});
};
const setUsername = (username) => {
const welcome = document.getElementById("welcome");
if (welcome !== null) welcome.innerText = "Welcome, " + username;
};
useEffect(() => {
if (reportRef.current !== null) {
const reportContainer = reportRef.current;
if (error.length) {
reportContainer.textContent = "";
error.forEach(line => {
reportContainer.appendChild(document.createTextNode(line));
reportContainer.appendChild(document.createElement("br"));
});
} else if (accessToken !== "" && embedUrl !== "") {
const embedConfiguration = {
type: "report",
tokenType: models.TokenType.Aad,
accessToken,
embedUrl,
id: config.reportId,
};
const report = powerbi.embed(reportContainer, embedConfiguration);
report.off("loaded");
report.on("loaded", () => {
console.log("Report load successful");
});
report.off("rendered");
report.on("rendered", () => {
console.log("Report render successful");
});
report.off("error");
report.on("error", (event) => {
const errorMsg = event.detail;
console.error(errorMsg);
});
}
}
}, [accessToken, embedUrl, error]);
useEffect(() => {
authenticate();
}, []);
useEffect(() => {
return () => {
if (reportRef.current) {
powerbi.reset(reportRef.current);
}
};
}, []);
return (
<div>
<div id="welcome"></div>
<div ref={reportRef}>
Loading the report...
</div>
</div>
);
};
I don’t get any error when I am running the project locally on port 3000. But when I deploy to the server I get following error
Uncaught BrowserAuthError: crypto_nonexistent: The crypto object or function is not available.
this project was created using CRA. How to solve this?