Single Sign-On (SSO) is a user authentication technique that allows users to sign in to many different applications without having to enter a login name and password for each application. SSO makes it easy for users to manage their accounts and reduces the number of times users have to enter login information.
Keycloak is a free and open source Identity and Access Management (IAM) system that allows you to build SSO solutions for web and mobile applications. Keycloak provides a user interface to manage users, accounts and access rights, and can integrate with various authentication systems such as LDAP, SAML, etc. Keycloak also supports security features like password security, two-factor authentication, etc.
To use SSO (Single Sign-On) Keycloak in React, you can do the following steps:
- Install keycloak-js library:
- First, you need to install the keycloak-js library with the following command:
1 2 | npm install keycloak-js |
- You can then instantiate a Keycloak object like so:
1 2 3 4 5 6 7 8 | import Keycloak from 'keycloak-js'; const keycloak = new Keycloak({ url: 'http://keycloak-server/auth', realm: 'myrealm', clientId: 'myclient', }); |
In the above code, we initialize Keycloak with the following information:
- url: Keycloak server address.
- realm: The realm name configured on the Keycloak server.
- clientId: The client name configured on the Keycloak server.
- Next, write a function that implements all the methods of the newly created keycloak object.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | import { KeycloakEnum } from "../enum/KeyCloakEnum"; import keycloak from "./keycloack"; const initKeycloak = (onAuthenticatedCallback: Function, logout: Function) => { // khởi tạo đối tượng keycloak keycloak.init({ onLoad: "check-sso", enableLogging: true, pkceMethod: "S256", silentCheckSsoRedirectUri: window.location.origin + '/silent-check-sso.html' }) .then((authenticated: boolean) => { if (!authenticated) { isSSO && logout(); } return onAuthenticatedCallback(); }) .catch((e) => { return console.error; }); }; const getKeyCloack = () => keycloak; const doLogin = keycloak.login; // đăng nhập const doLogout = keycloak.logout; // đăng xuất const getToken = () => keycloak.token; // lấy token const isLoggedIn = () => keycloak.authenticated; // kiểm tra trạng thái đăng nhập const getUsername = () => keycloak.tokenParsed?.realm_access; // lấy thông tin user const hasRole = (roles: string[]) => roles.some((role: string) => keycloak.hasRealmRole(role)); // kiểm tra quyền const UserService = { initKeycloak, doLogin, doLogout, isLoggedIn, getToken, getUsername, hasRole, getKeyCloack }; export default UserService; |
- Use the function just created above in the application’s container class to check the login:
1 2 3 4 5 6 7 8 | // code khởi tạo ứng dụng.... UserService.initKeycloak(renderApp, () => { action.clearAuthentication(); action.clearSearchInfo(); action.clearSitesMap(); }); |
- After the initialization is complete, we create 2 router classes to navigate for the application:
- The class is only accessible when logged in:
1 2 3 4 5 6 7 8 9 10 11 | export default function AuthenticationRouter(props: { children: JSX.Element }) { const { children } = props; const auth = UserService.isLoggedIn(); //kiểm tra đã đăng nhập chưa bằng method isLoggedIn của keycloak if (auth) { return children; } else { return <Navigate to="/login" />; } } |
- Class accessed without login will check against the above class:
1 2 3 4 5 6 7 8 9 10 11 12 | export default function ProtectedRouter(props: { children: JSX.Element }) { const { children } = props; const location = useLocation(); const auth = UserService.isLoggedIn(); if (!auth) { return children; } else { return <Navigate to="/" state={{ from: location }} />; } } |
- Connect API:
- After the user is successfully logged in, you can use the user access token to call APIs that require authentication. To get the access token, you can use the keycloak.token method. Eg:
1 2 3 4 5 6 | axios.get('http://api-server/protected-resource', { headers: { Authorization: `Bearer ${UserService.getToken()}`, }, }); |
- References for use with other frameworks: https://keycloak-docs.github.io/deploy-docs/dev/master/securing_apps/index.html#_javascript_adapter