Search code examples
javascriptreactjsazure-active-directorymicrosoft-graph-apionelogin

Microsoft SSO login is not working as intended in react app


I am trying to do a microsoft SSO login in my react application using dynamic credentials for SSO login of client id, tenant id. The problem is that it is not working. It will just open a popup page and when I click on the user account it will just simple redirect to redirect url in the same page instead of closing up and returning me the result.

This happens when I am getting same credentials from database but when i am using them hardcoded it is working perfectly as it needs to be.

I have checked the data which I get from database and it is working fine there so trying to resolve it but I have no idea why it is behaving in this way.

here is my code below

function LoginButton() {
  const { instance } = useMsal();

  const handleLogin = async() => {
    instance.loginPopup().then((response) => {
      console.log(response);
    }).catch((error) => {
      console.log(error);
    });
  }

  return <button type="button" onClick={handleLogin} className="btn btn-primary">Login</button>;
}

function App() {
  const [msalConfig, setMsalConfig] = useState<Configuration | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  
  useEffect(() => {
    const MFTLogin = async () => {
      const subdomain = window.location.hostname.split('.')[0];
      const storedConfig = localStorage.getItem('msalConfig');

      if (storedConfig) {
        setMsalConfig(JSON.parse(storedConfig));
        setIsLoading(false);
      } else if (subdomain) {
        // Fetch and set MSAL configuration
        const request = await axios.get(`http://localhost:5000/outlook/organization/${subdomain}`);
        if (request && request.data) {
          const data: Configuration = {
            auth: {
              clientId: request.data.data.outlook_client_id_mfo,
              authority: `https://login.microsoftonline.com/${request.data.data.outlook_tenant_id_mfo}`,
              redirectUri: "http://localhost:3000",
            }
          };
          localStorage.setItem('msalConfig', JSON.stringify(data));
          setMsalConfig(data);
        }
        setIsLoading(false);
      }
    };

    MFTLogin();
  }, []);

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (!msalConfig) {
    return <div>Configuration Error</div>;
  }

  const msalInstance = new PublicClientApplication(msalConfig);

  return (
    <MsalProvider instance={msalInstance}>
      <div className="App">
        <LoginButton />
      </div>
    </MsalProvider>
  );
}

export default App;

Solution

  • I tried the below code and was able to log in to my react application using dynamic credentials for SSO login of client ID, tenant ID.

    Code :

    src/components/LoginButton.js :

    import React from 'react';
    import { useMsal } from '@azure/msal-react';
    import { setMsalConfig } from '../services/authService'; 
    import { fetchMsalConfigFromApi } from '../services/apiService'; 
    
    const LoginButton = () => {
      const { instance } = useMsal();
    
      const handleLogin = async () => {
        let apiConfig; 
    
        try {
          const subdomain = window.location.hostname.split('.')[0];
          apiConfig = await fetchMsalConfigFromApi(subdomain);
    
          setMsalConfig({
            auth: {
              clientId: apiConfig.outlook_client_id_mfo,
              authority: `https://login.microsoftonline.com/${apiConfig.outlook_tenant_id_mfo}`,
              redirectUri: 'http://localhost:3000',
            },
          });
    
          await instance.loginPopup();
        } catch (error) {
          console.log('Error during login:', error);
        }
      };
    
      return (
        <button type="button" onClick={handleLogin} className="btn btn-primary">
          Login
        </button>
      );
    };
    
    export default LoginButton;
    

    src/services/apiService.js :

    import axios from 'axios';
    const fetchMsalConfigFromApi = async (subdomain) => {
      try {
        const response = await axios.get(`http://localhost:5000/outlook/organization/`);
        return response.data.data;
      } catch (error) {
        console.error('Error fetching MSAL config from API:', error);
        throw error;
      }
    };
    
    export { fetchMsalConfigFromApi };
    

    server/server.js :

    const express = require('express');
    const cors = require('cors');
    const app = express();
    const port = 5000;
    
    const msalConfig = {
      outlook_client_id_mfo: '<client_ID>',
      outlook_tenant_id_mfo: '<tenant_ID>',
    };
    
    app.use(cors());
    
    app.get('/outlook/organization', (req, res) => {
      res.json({
        success: true,
        data: msalConfig,
      });
    });
    
    app.listen(port, () => {
      console.log(`Server is running on port ${port}`);
    });
    

    I added the below URL as a Single-page application in the app authentication as below,

     http://localhost:3000
    

    enter image description here

    Output :

    The server side code is running on the port 5000 as below,

    enter image description here

    I got the below output with the above output URL in the browser,

    enter image description here

    The client-side code is running on port 3000 as below,

    enter image description here

    I clicked on the Login button and selected my account for login. I was able to log in.

    enter image description here