react-and-keycloak
v0.1.0
Published
Keycloak + React Router - Clean & Simple.
Downloads
14
Maintainers
Readme
react-and-keycloak
A simple interface to use React Router and Keycloak together.
It is a thin wrapper around @react-keycloak/web
that makes everything nice and easy to use. I also ported over and simplified the logic from react-router-keycloak
which
Usage
In index.jsx
import React from 'react';
import KeycloakProvider from 'react-and-keycloak';
import Routes from './routes';
const kcParams = {
url: 'https://auth.mydomain.com',
realm: 'master', // optional
// a public client cuz you dont wanna put a clientSecret on a public webpage
clientId: 'myclient',
};
const App = ({}) => {
return (
<KeycloakProvider {...kcParams} onEvent={console.log} onTokens={console.log}>
<Routes />
</KeycloakProvider>
)
}
And then in routes.jsx
import { useKeycloak } from '@react-keycloak/web';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import { PrivateRoute, LoginRoute, LogoutRoute } from 'react-and-keycloak';
function Routes() {
const { initialized, keycloak } = useKeycloak();
if (!initialized) {
return <div>Loadinggggg...</div>
}
const token = keycloak && keycloak.token;
return (
<main>
<Router>
<Route exact path="/" render={() =>
<div>
A public home page <p>Token: {token}</p>
</div>} />
<LoginRoute redirectTo="/token" />
<LogoutRoute redirectTo="/" />
<PrivateRoute path="/private" render={() =>
<div>
A private page <p>Token: {token}</p>
<Link to="/private2">other</Link>
</div>} />
<PrivateRoute path="/private2" render={() =>
<div>
Another private page <p>Token: {token}</p>
<Link to="/private">other</Link>
</div>} />
</Router>
</main>
)
}
API Reference
KeycloakProvider
This is responsible for holding the Keycloak JS object and providing it to the child elements. This goes at the top of the DOM hierarchy.
// defaults
<KeycloakProvider {...{
// connection parameters for keycloak
url, // the keycloak base url
clientId, // the keycloak client id
realm='master', // the keycloak realm
loginPath='/login', // the login route to redirect to
logoutPath='/logout', // TODO: how to connect these to login routes
onTokens, // callback function when tokens are refreshed. receives ({ token, refreshToken, idToken })
// keycloak api reference: https://www.keycloak.org/docs/latest/securing_apps/#javascript-adapter-reference
initOptions, // keycloak .init() arguments
keycloakOptions, // keycloak() arguments
offline=false, // use an offline refresh token (basically refresh token won't expire, but it's higher risk)
appendPath=null, // set to false if you don't want to append /auth to your url (you probably do tho)
children, // children components that can access the keycloak object
...props
}} />
For keycloak options: docs For init options: docs
Example
The simplest configuration you could provide:
<KeycloakProvider url='auth.myproject.com' clientId='myapp'>
<App />
</KeycloakProvider>
PrivateRoute
This let's you create a react router route that is only accessible when you're logged in.
If you aren't, it will redirect you to the Keycloak login page.
<PrivateRoute {...{
render, // the route render function
...routeProps, // the rest of the route props
}}>
Example
<Router>
<PrivateRoute path="/private" render={() =>
<div>I am a dark secret</div>} />
</Router>
LoginRoute
<LoginRoute {...{
path, // the url for the login page - make sure it matches with `KeycloakProvider`'s `loginPath`
redirectTo, // the url to redirect to when you're done
...routeProps, // the rest of the route props
}}>
Example
<Router>
<LoginRoute redirectTo="/" />
</Router>
LogoutRoute
<LogoutRoute {...{
path, // the url for the logout page - make sure it matches with `KeycloakProvider`'s `logoutPath`
redirectTo, // the url to redirect to when you're done
...routeProps, // the rest of the route props
}}>
Example
<Router>
<LogoutRoute redirectTo="/" />
</Router>
Protect
This is a slightly more general version of PrivateRoute
that will only render its children
<Protect {...{
children, // a function that returns the protected children
unprotected // an optional function that returns content to render for unauthenticated users
}} />
Example
<Protect>() => (<div>You're only gonna see this if you're logged in !!!</div>)</Protect>
And if you want to display a message for unauthenticated users:
<Protect unprotected={() => <div>Ma says not to talk to strangers !!</div>}>
() => (<div>Oh hey friend !!</div>)
</Protect>
Other Routes
See keycloak docs.
NOTE: The path parameters here are set to their defaults and are optional. They are included here for clarity.
<Router>
<LoginRoute />
<LogoutRoute />
<RegisterUrl path='/register' /> {/* Redirects to Keycloak's register url */}
<ManageAccountUrl path='/account' /> {/* Redirects to Keycloak's account url */}
</Router>
Utilities
useToken
const {
token, // the token string
data // the token payload
} = useToken(
period=null, // the interval to check the token - by default it's 1 (second), for key='refresh' it's 10(s).
key=null // the kind of token to get. can be null, 'refresh', or 'id'
);
Example
To get your token as a string (token
) and it's contents as an object (data
) use this:
import { useToken } from 'react-and-keycloak';
const App = () => {
const { token, data } = useToken();
return (<div>
<p>Your token, dear: {token}</p>
<p>anddd the data: {JSON.stringify(data)}</p>
</div>);
}
If, for some reason, you want the refresh token, you can do useToken(null, 'refresh')
or useToken(null, 'id')
for the id token.
It will periodically check if there's a new token and will refresh when a new one is available.
If you want to
By default, it will check refresh tokens every 10 seconds and the others every 1 second.
timeLeft
// given the token payload, return the time left in seconds until expiration
const seconds = timeLeft(data);
To get the time left in your token, do this:
import { useToken, timeLeft } from 'react-and-keycloak';
const App = () => {
const { token, data } = useToken();
// this will only update when you get a new token.
return <div>You have {timeLeft(data)} seconds left in your token.</div>
}
useTock
// re-render every x seconds. returns the current time
// by default, it uses 1 second
const tock = useTock(1);
If you want to refresh your elements on your own every second, you can do:
import { useTock, useToken, timeLeft } from 'react-and-keycloak';
const App = () => {
useTock(1); // will refresh every 1 second
const { token, data } = useToken();
// now timeleft will update every second
return <div>You have {timeLeft(data)} seconds left in your token.</div>
}
or alternatively:
import { useTock, useToken, timeLeft } from 'react-and-keycloak';
const App = () => {
const { token, data } = useToken();
return <TimeLeftDisplay data={data} />
}
const TimeLeftDisplay = ({ data }) => {
const tock = useTock(1); // now tock is only refreshing what it needs to
return <div>You have {timeLeft(data)} seconds left in your token.</div>
}