I am building a demon project of authentication whith Keycloak into a react project. I have one public page and a private one. The private page check if the user is logged in and display a button to log in or to log out, depending the connection state. This part works well. When I click on the log in button I am redirected to the Keycloak portal. After login, I am redirected to the private page and I can log out with the apropriated button.
But when I navigate to the public page and go back to the private, or just refreshing the private page, the connection seems to be out. Then I click on the log in button and the connection come back, without been redirected to the keycloak portal.
There the private page :
import React from "react";
import Nav from "../modules/Nav";
import RenderAnonymous from "../modules/RenderAnonymous";
import RenderAuthenticated from "../modules/RenderAuthenticated";
import UserService from "../services/UserService";
const Private = () => {
return (
<>
<Nav/>
<RenderAnonymous>
<p>Il faut s'authentifier</p>
<button onClick={UserService.doLogin} className="btn login-btn">Se connecter</button>
</RenderAnonymous>
<RenderAuthenticated>
<p>User info</p>
<button onClick={UserService.doLogout} className="btn login-btn">Déconnexion</button>
</RenderAuthenticated>
<div className="private">
<h2>Page privée</h2>
</div>
</>
);
};
export default Private;
RenderAnonymous and RenderAuthenticated are the same expect the authentication condition :
import UserService from "../services/UserService";
const RenderAuthenticated = ({children}) => {
if (UserService.isAuthenticated()) {
return (children);
}
return null;
};
export default RenderAuthenticated;
UserService :
import keycloak from "keycloak-js";
const KC = new keycloak("/keycloak.json");
const initKeycloak = (authenticatedCllback) => {
KC.init({
onLoad: "check-sso"
}).then((auth)=>{
if (auth) {
console.info("Already logged in");
} else {
console.info("Need to log in");
}
authenticatedCllback();
}).catch((err)=>{
console.error(err);
});
}
const doLogin = () => {
return KC.login();
}
const doLogout = () => {
return KC.logout();
}
const isAuthenticated = () => {
return KC.authenticated;
}
const UserService = {
initKeycloak,
doLogin,
doLogout,
isAuthenticated,
};
export default UserService;
The inistialization of keycloak is launched from index.js :
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import UserService from "./services/UserService";
const renderApp = () => ReactDOM.render(<App/>,document.getElementById("root"));
UserService.initKeycloak(renderApp);
I don't understand where is the problem... Is it a problem of flow ? https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_implicit_flow
From my point of view, you should integrate the keycloak object (and the UserService) into react handling. At the moment it seems to live outside of your <App/>
.
For example you can use React context to hold the keycloak instance. But you do not need to implement this yourself. There is already a library called react-keycloak which implements this approach.