Framework Agnostic Adapter
Installation
1
2
Global Setup
import { defineConfig } from "vite";
import { oidcSpa } from "oidc-spa/vite-plugin";
export default defineConfig({
plugins: [
// ...
oidcSpa()
]
});mv src/main.ts src/main.lazy.tsimport { oidcEarlyInit } from "oidc-spa/entrypoint";
const { shouldLoadApp } = oidcEarlyInit({
BASE_URL: "/" // The path where your app is hosted
// If applicable you should use `process.env.PUBLIC_URL`
// or `import.meta.env.BASE_URL`.
// This is not an option. There's only one good answer.
});
if (shouldLoadApp) {
// Note: Deferring the main app import adds a few milliseconds to cold start,
// but dramatically speeds up auth. Overall, it's a net win.
import("./main.lazy");
}3
Initialize the adapter
import { createOidc } from "oidc-spa/core";
import { z } from "zod";
const prOidc = createOidc({
// See: https://docs.oidc-spa.dev/v/v9/providers-configuration/provider-configuration
issuerUri: "https://auth.your-domain.net/realms/myrealm",
clientId: "myclient",
// Optional. Expected shape of the ID token payload.
// This is declarative. You describe what you will use and what
// info you expect to be present in the ID token.
// If you don't know what's in your ID token, open the console.
// If you have debugLogs set to true, you'll see it.
decodedIdTokenSchema: z.object({
preferred_username: z.string(),
name: z.string(),
email: z.string().optional(),
picture: z.string().optional(),
realm_access: z.object({ roles: z.array(z.string()) }).optional()
}),
//scopes: ["profile", "email", "api://my-app/access_as_user"],
// OPTIONAL, Parameters added when redirecting to the authorization endpoint.
extraQueryParams: {
//audience: "https://my-app.my-company.com/api",
get ui_locales() { return "en"; } // Keycloak login/register pages language
},
debugLogs: true,
// See: https://docs.oidc-spa.dev/v/v8/features/auto-login
// autoLogin: true
// See: https://docs.oidc-spa.dev/v/v8/features/dpop
// dpop: "auto"
});
export async function getOidc(){
const oidc = await prOidc;
return oidc;
}Usage
import { getOidc } from "~/oidc"; // The file you created in the previous step
(async () => {
const oidc = await getOidc();
// oidc-spa exports Keycloak-specific utilities:
const { createKeycloakUtils, isKeycloak } = await import("oidc-spa/keycloak");
const keycloakUtils = isKeycloak({ issuerUri: oidc.issuerUri })
? createKeycloakUtils({ issuerUri: oidc.issuerUri })
: undefined;
// In oidc-spa the user is either logged in or they aren't.
// The state will never mutate without a full app reload.
if (oidc.isUserLoggedIn) {
// The user is logged in.
const {
// The accessToken is what you'll use as a Bearer token to
// authenticate to your APIs
accessToken
} = await oidc.getTokens();
// oidc-spa also provides utilities to build API clients like this.
fetch("https://api.your-domain.net/orders", {
headers: {
Authorization: `Bearer ${accessToken}`
}
})
.then(response => response.json())
.then(orders => console.log(orders));
// Call when the user clicks logout.
// You can also redirect to a custom URL with:
// { redirectTo: "specific URL", url: "/bye" }
oidc.logout({ redirectTo: "home" });
const decodedIdToken = oidc.getDecodedIdToken();
console.log(`Hello ${decodedIdToken.preferred_username}`);
if (keycloakUtils) {
// Get a link to the account page:
const userAccountUrl = keycloakUtils.getAccountUrl({
clientId: oidc.clientId,
validRedirectUri: oidc.validRedirectUri,
locale: "en" // Optional
});
}
} else {
// The user is not logged in.
// We can call login() to redirect the user to the login/register page.
// This returns a promise that never resolves.
oidc.login({
/**
* If you are calling login() in the callback of a click event
* set this to false.
* If you are calling this because the user has navigated to
* a route that requires them to be logged in, set this to true.
*/
doesCurrentHrefRequiresAuth: false,
/**
* Optionally, you can add extra parameters
* to be added to the authorization endpoint.
*/
//extraQueryParams: { kc_idp_hint: "google", ui_locales: "fr" }
/**
* You can also set where to redirect the user after
* successful login but by default it's the current URL
* which is usually what you want.
*/
// redirectUrl: "/dashboard"
});
// Register button callback (Keycloak only)
if (keycloakUtils) {
oidc.login({
doesCurrentHrefRequiresAuth: false,
transformUrlBeforeRedirect: keycloakUtils.transformUrlBeforeRedirectForRegister
});
}
}
})();Mock adapter
Creating an API server
Backend Token ValidationLast updated
Was this helpful?