1

I am using the OIDC client to perform the authentication and authorization using react application. I am able to login successful after the login I have a nav menu to display if the user is authenticated or not.

export default function NavMenu() {
    const authService = new AuthService();
    useSelector((state: ApplicationState) => state.oidcUser);
    const dispatch = useDispatch();
    const [state, setState] = useState({
        isLogedIn: false
    });
    const [open, setOpen] = React.useState(false);
    const close = () => {
        setOpen(false);
    };
    const menuClick =() => {
        setOpen(!open);
    };

    useEffect(() => {
        authService.getUser().then((user: any) => {
            if (user != null)
                setState({ isLogedIn: true });
            else
                setState({ isLogedIn: false })
        });

    });

    const login = () => {
        authService.startAuthentication(window.location.pathname);
    };
    const logout = () => {
        authService.logout();
    };

    const menuOptions = [
        'Save',
        'Edit',
        'Cut',
        'Copy',
        'Paste',
    ];

    return (<div>
        <TopAppBar>
            <TopAppBarRow>
                <TopAppBarSection align='start'>
                    <TopAppBarTitle>Falcon</TopAppBarTitle>
                </TopAppBarSection>
                <TopAppBarSection align='end' role='toolbar'>
                    <div>
                        {(() => {
                            if (!state.isLogedIn) {
                                return (
                                    <Button raised type="button" onClick={login}>Portal</Button>
                                )
                            } else {
                                return (
                                    <div>
                                        <Menu
                                            open={open}
                                            onClose={close}
                                            onSelected={(index, item) => console.log(index, item)}>
                                            <MenuList>
                                                {menuOptions.map((option, index) => (
                                                    <MenuListItem key={index}>
                                                        <MenuListItemText primaryText={option} />
                                                        {/* You can also use other components from list, which are documented below */}
                                                    </MenuListItem>
                                                ))}
                                            </MenuList>
                                        </Menu>
                                        <Fab onClick={menuClick} icon={<MaterialIcon icon="account_circle" />} />
                                    </div>
                                )
                            }
                        })()}
                    </div>
                </TopAppBarSection>
            </TopAppBarRow>
        </TopAppBar>
    </div>);
}

If I use the method

useEffect(() => {
            authService.getUser().then((user: any) => {
                if (user != null)
                    setState({ isLogedIn: true });
                else
                    setState({ isLogedIn: false })
            });
        });

I get the infinite loop on the connect/checksession API from the identity server. If I remove the method the if condition (state.isLogedIn) to display the menu doesn't work.

How can I handle the user is logedin properly. What is the best method to do the OIDC client authentication and authorization in react.

Auth service

export class AuthService {
    public userManager: UserManager;
    private user: any = null;

    constructor() {
        const settings = this.getClientSettings();
        this.userManager = new UserManager(settings);
    }


    public isLoggedIn(): boolean {
        return this.user != null && this.user.access_token && !this.user.expired;
    }

    public getUser(): Promise<User | null> {
        return this.userManager.getUser().then((user) => this.user = user);
    }

    public login(): Promise<void> {
        return this.userManager.signinRedirect();
    }
    public logout(): Promise<void> {
        return this.userManager.signoutRedirect(this.getClientSettings().post_logout_redirect_uri);
    }

    public startAuthentication(returnUrl: string) {
        Log.info("[AuthService] startAuthentication", returnUrl);
        this.userManager.clearStaleState();
        this.userManager.signinRedirect({ data: { returnUrl: returnUrl } }).then(user => this.user = user).catch(err => {
            this.handleError(err);
            return err;
        });
    }

    private getClientSettings(): any {
        return {
            authority: "https://localhost:5001",
            client_id: "Local",
            redirect_uri: "https://localhost:5001/auth-callback",
            post_logout_redirect_uri: "https://localhost:5001",
            response_type: "code",
            automaticSilentRenew: true,
            scope: "profile openid email IdentityPortal.API offline_access",
            //filterProtocolClaims: environment.openID.filterProtocolClaims,
            loadUserInfo: true,
            monitorSession: true,
            silent_redirect_uri: "https://localhost:5001/silent-reniew.html",
            accessTokenExpiringNotificationTime: 20, //default 60
            //checkSessionInterval: 86400, //default 2000
            //silentRequestTimeout: 2000,
        };
    }

    handleError(error: any) {
        Log.error(error)
    }
}
San Jaisy
  • 15,327
  • 34
  • 171
  • 290

1 Answers1

0

If you want something to compare against, maybe have a look at my React sample:

My equivalent of your AuthService is my Authenticator. If you are getting a redirect loop then it may be because you are not calling OIDC Client's signInRedirectCallback() method to process the login response. I couldn't see a reference to that call in your code.

Gary Archer
  • 22,534
  • 2
  • 12
  • 24