React Router
The example setup is live here: https://example-react-router.oidc-spa.dev/
Run it locally with:
npx degit https://github.com/keycloakify/oidc-spa/examples/react-router oidc-spa-react-router
cd oidc-spa-react-router
cp .env.local.sample .env.local
yarn
yarn dev
This is for setting for integrating oidc-spa with react-router in Framework Mode
.
Enabling SPA mode
As of today, to use oidc-spa you need to enable SPA mode.
import type { Config } from "@react-router/dev/config";
export default {
// Config options...
// Server-side render by default, to enable SPA mode set this to `false`
ssr: false
} satisfies Config;
oidc.client.ts
Make sure you create a app/oidc.client.ts
file, (instead of app/oidc.ts
).
Setting up the entrypoint
Create thoses two files:
Working with loaders
If your whole app requires user to be authenticated (autoLogin: true) you can skip this section.
The default approach when you want to enforce that the user be logged in when accesing a given route is to wrap the component into withLoginEnforced()
, example:
import { useState, useEffect } from "react";
import { withLoginEnforced, fetchWithAuth } from "../oidc.client";
const Invoices = withLoginEnforced(
() => {
const [invoices, setInvoices] = useState<Invoice[] | undefined>(undefined);
useEffect(() => {
fetchWithAuth("/api/invoices")
.then(r => r.json())
.then(setInvoices);
}, []);
if (invoices === undefined) {
return <div>Loading invoices...</div>;
}
return (
<div>
{invoices.map(invoice => (
<div key={invoice.id}>{invoice.amount}</div>
))}
</div>
);
},
{
onRedirecting: () => <div>Redirecting to login...</div>
}
);
export default Invoices;
This approach is framework agnostic and always works however, you might want to use the loaders to doload the data, for that you would use enforceLogin()
istead of withLoginEnforced
:
import { enforceLogin, fetchWithAuth } from "../oidc.client";
import type { Route } from "./+types/invoices";
import { useLoaderData } from "react-router";
export async function clientLoader(params: Route.ClientLoaderArgs) {
await enforceLogin(params);
// If we are here, the user is logged in.
const invoices = await fetchWithAuth("/api/invoices").then(r => r.json());
return invoices;
}
export function HydrateFallback() {
return <div>Loading invoices...</div>;
}
export default function Invoices() {
const invoices = useLoaderData<typeof clientLoader>();
return (
<div>
{invoices.map(invoice => (
<div key={invoice.id}>{invoice.amount}</div>
))}
</div>
);
}
Running the example
The example setup is live here: https://example-react-router-framework.oidc-spa.dev/
Run it locally with:
npx degit https://github.com/keycloakify/oidc-spa/examples/react-router-framework oidc-spa-react-router
cd oidc-spa-react-router
cp .env.local.sample .env.local
yarn
yarn dev
Last updated
Was this helpful?