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)
}
}