Before getting started, you need to get a hold of the few parameters required to connect to your OIDC provider.
Find instruction on how to configure your OIDC provider on the following documentation page:
import { createOidc } from"oidc-spa";import { z } from"zod";constoidc=awaitcreateOidc({ issuerUri:"https://auth.your-domain.net/realms/myrealm", clientId:"myclient",/** * Vite: `homeUrl: import.meta.env.BASE_URL` * CRA: `homeUrl: process.env.PUBLIC_URL` * Other: `homeUrl: "/"` (Usually, can be something like "/dashboard") */ homeUrl:import.meta.env.BASE_URL,//scopes: ["profile", "email", "api://my-app/access_as_user"],extraQueryParams: () => ({ ui_locales:"en"// Keycloak login/register page language//audience: "https://my-app.my-company.com/api" }), decodedIdTokenSchema:z.object({ preferred_username:z.string(), name:z.string()//email: z.string().email().optional() })});if (!oidc.isUserLoggedIn) {// The user is not logged in.// We can call login() to redirect the user to the login/register page.// This return a promise that never resolve. oidc.login({/** * If you are calling login() in the callback of a click event * set this to false. */ doesCurrentHrefRequiresAuth:false/** * Optionally, you can add some extra parameter * to be added on the login url. * (Can also be a parameter of createOidc `extraQueryParams: ()=> ({ ui_locales: "fr" })`) *///extraQueryParams: { kc_idp_hint: "google", ui_locales: "fr" }/** * You can allso set where to redirect the user after * successful login */// redirectUrl: "/dashboard"/** * Keycloak: You can also send the users directly to the register page * see: https://github.com/keycloakify/oidc-spa/blob/14a3777601c50fa69d1221495d77668e97443119/examples/tanstack-router-file-based/src/components/Header.tsx#L54-L66 */ });} else {// The user is logged in.const {// The accessToken is what you'll use as a Bearer token to // authenticate to your APIsaccessToken } =awaitoidc.getTokens_next();fetch("https://api.your-domain.net/orders", { headers: { Authorization:`Bearer ${accessToken}` } }).then(response =>response.json()).then(orders =>console.log(orders));// To call when the user click on logout.// You can also redirect to a custom url with // { redirectTo: "specific url", url: "/bye" }oidc.logout({ redirectTo:"home" });constdecodedIdToken=oidc.getDecodedIdToken();console.log(`Hello ${decodedIdToken.preferred_username}`);}
The way you use oidc-spa differs slightly depending on the routing library you’re using (e.g., React Router or TanStack Router).
We provide specific setup guides for each, but we recommend starting with the fictional example below to understand how the library works in isolation, without any routing-related distractions.
Note: In this example, some pages can be accessed without requiring the user to be authenticated.
If you're building something like an admin panel or a dashboard where authentication is always required, simply set autoLogin: true.
import { useEffect, useState } from "react";
import { withLoginEnforced, fetchWithAuth } from "../oidc";
type Order = {
id: number;
name: string;
};
// If this component is mounted and the user is not logged in
// the user will be redirected to the login.
// If your routing library support loader you can use enforceLogin
// instead of withLoginEnforced
const Page = withLoginEnforced(() => {
const [orders, setOrders] = useState<Order[] | undefined>(undefined);
useEffect(() => {
fetchWithAuth("https://api.your-domain.net/orders", {
headers: {
"Content-Type": "application/json"
}
})
.then(response => response.json())
.then(orders => setOrders(orders));
}, []);
if (orders === undefined) {
return <>Loading orders ⌛️</>;
}
return (
<ul>
{orders.map(order => (
<li key={order.id}>{order.name}</li>
))}
</ul>
);
});
export default Page;