1

I have created a basic application of react in which I have implemented the concept of routing and for authentication I have used Azure AD. Its working fine when I try to login using the login button but I want that when I try to access the home page it automatically redirects to the login page(Microsoft login) without clicking any button.

This is my code for "App.js" and in "AuthConfig" I have simply declared my clientId, redirecturi, scopes and authority.


import Prices from "./pages/Prices";
import Ticket from "./pages/Ticket";
import Money from "./pages/Money";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import {config} from "./AuthConfig";
import {PublicClientApplication} from '@azure/msal-browser';
import React from "react";

class App extends React.Component<any, any>{
  publicClientApplication: PublicClientApplication;  
  constructor(props){
    super(props);
    this.state = {
      error: null,
      isAuthenticated: false,
      user:{}
    };
    this.login=this.login.bind(this)
    
    this.publicClientApplication = new PublicClientApplication({
      auth:{
        clientId: config.appId,
        redirectUri: config.redirectUri,
        authority: config.authority
      },
      cache:{
        cacheLocation: "sessionStorage",
        storeAuthStateInCookie: false
      }
    });
  }
  async login(){
    try{
      
      await this.publicClientApplication.loginPopup(
        {
        scopes: config.scopes,
        prompt:"select_account"
      });
      this.setState({isAuthenticated:true})
  }
  catch(err){
    this.setState({
      isAuthenticated:false,
      user:{},
      error:err
    });
  }
}
logout(){
  this.publicClientApplication.logoutPopup();
}

render() {
  return(
    <div className="App">
     
      {this.state.isAuthenticated ? <p>
        <BrowserRouter>
        <Routes>
          <Route path="/" element={<Prices />} />
        </Routes>
      </BrowserRouter>
      </p>: 
      <p>
        <button onClick={() => this.login()} > Login </button>
      </p>
      }
      <BrowserRouter>
        <Routes>         
          <Route path="/Money" element={<Money />}></Route>
          <Route path="/Ticket" element={<Ticket/>}></Route>
        </Routes>
      </BrowserRouter>
      
     
    </div>
  );
}
}
export default App;

Avanish
  • 51
  • 6
  • You know that popups that open on websites without any user interaction are usually spam? Popup blockers in browsers typically block these. You might need to use loginRedirect instead as you can do redirects without interaction. – juunas Nov 30 '22 at 13:10
  • Does this help answer your question for a general "how do I redirect for authentication using react-router-don"? https://stackoverflow.com/a/66289280/8690857 – Drew Reese Nov 30 '22 at 16:42
  • @DrewReese No its not working in my case – Avanish Dec 01 '22 at 11:51
  • No, *what* is not working in your case? Can you be more specific? – Drew Reese Dec 01 '22 at 17:58
  • @DrewReese I have created a UI for login using Azure AD and the login page is opening when I click on login button, but I want to open the login page automatically when my localhost gets fired. – Avanish Dec 02 '22 at 15:28
  • If the login UI is rendered based on clicking a button, is there a reason you can't just trigger that login UI programmatically (*i.e. when a component mounts*) instead of as an asynchronous UI event (*i.e. in response to a button being clicked*)? You just want that `login` function to be called without user interaction? What is the condition you want this to happen? – Drew Reese Dec 02 '22 at 17:15
  • @DrewReese So my point is, when I run my react application using "yarn start" it opens a page with that login button and when we click on that login button it opens the login screen which is done using Azure AD in my case. But I want to open the Azure AD login screen directly when I run "yarn start" command. – Avanish Dec 05 '22 at 06:43
  • Right, I think I get that part. Why can't your app code just directly open the login screen instead of waiting for a button to be pressed? – Drew Reese Dec 05 '22 at 06:44
  • @DrewReese I have tried the same but its not working properly as the routing is getting called everytime and the page gets logout by itself. – Avanish Dec 06 '22 at 11:18

1 Answers1

1

If you simply want the login function to be called automatically when the App component mounts instead of when the button is clicked you can do this in the componentDidMount lifecycle method.

Example:

class App extends React.Component<any, any> {
  publicClientApplication: PublicClientApplication;

  constructor(props) {
    super(props);
    this.state = {
      error: null,
      isAuthenticated: false,
      user: {}
    };

    this.publicClientApplication = new PublicClientApplication({
      auth: {
        clientId: config.appId,
        redirectUri: config.redirectUri,
        authority: config.authority
      },
      cache: {
        cacheLocation: "sessionStorage",
        storeAuthStateInCookie: false
      }
    });
  }

  componentDidMount() {
    this.login();
  }

  login = sync () => {
    try {
      await this.publicClientApplication.loginPopup({
        scopes: config.scopes,
        prompt: "select_account"
      });
      this.setState({ isAuthenticated: true });
    } catch(err) {
      this.setState({
        isAuthenticated: false,
        user: {},
        error: err
      });
    }
  }

  logout() {
    this.publicClientApplication.logoutPopup();
  }

  render() {
    return(
      <div className="App">
        {this.state.isAuthenticated && (
          <BrowserRouter>
            <Routes>
              <Route path="/" element={<Prices />} />
            </Routes>
          </BrowserRouter>
        )}
        <BrowserRouter>
          <Routes>
            <Route path="/Money" element={<Money />} />
            <Route path="/Ticket" element={<Ticket />} />
          </Routes>
        </BrowserRouter>
      </div>
    );
  }
}

I'm also not sure what is going on with usage of two routers, you'll very likely want to merge these so all routes are rendered within the same single routing context.

Example:

<div className="App">
  <BrowserRouter>
    <Routes>
      <Route
        path="/"
        element={this.state.isAuthenticated ? <Prices /> : null}
      />
      <Route path="/Money" element={<Money />} />
      <Route path="/Ticket" element={<Ticket />} />
    </Routes>
  </BrowserRouter>
</div>
Drew Reese
  • 165,259
  • 14
  • 153
  • 181