Tokens Renewal
oidc-spa completely abstracts away the concern of refreshing tokens; you don’t need to handle it yourself.
However, it still provides a renewTokens() function for a couple of rare but valid edge cases:
Force update after custom requests: If you send a custom request to your OIDC server (e.g., Keycloak) that you know has changed some claims in the
id_tokenoraccess_token, you can callrenewTokens()to ensure you’re working with the latest values.Custom parameters to the token endpoint: If your OIDC server’s token endpoint accepts special parameters,
renewTokens()lets you trigger a refresh that including custom parameters (there is also theextraTokenParamsoption that you can provide tocreateOidc.).
import { createOidc } from "oidc-spa";
const prOidc = await createOidc({ ... });
// Function to call when we want to renew the token
export function renewTokens(){
const oidc = await prOidc;
if( !oidc.isUserLoggedIn ){
throw new Error("Logical error");
}
oidc.renewToken(
// Optionally you can pass extra params that will be added
// to the body of the POST request to the openid-connect/token endpoint.
// { extraTokenParams: { electedCustomer: "customer123" } }
// This parameter can also be provided as parameter to the createOidc
// function. See: https://github.com/keycloakify/oidc-spa/blob/59b8db7db0b47c84e8f383a86677e88e884887cb/src/oidc.ts#L153-L163
);
}
// Subscribing to token renewal
prOidc.then(oidc => {
if( !oidc.isUserLoggedIn ){
return;
}
const { unsubscribe } = oidc.subscribeToTokensChange(tokens => {
console.log("Token Renewed", tokens);
});
setTimeout(() => {
// Call unsubscribe when you want to stop watching tokens change
unsubscribe();
}, 10_000);
});Outside of a React Component:
import { createReactOidc } from "oidc-spa/react";
const prOidc = await createReactOidc({ ... });
// Function to call when we want to renew the token
export function renewTokens(){
const oidc = await prOidc;
if( !oidc.isUserLoggedIn ){
throw new Error("Logical error");
}
oidc.renewToken(
// Optionally you can pass extra params that will be added
// to the body of the POST request to the openid-connect/token endpoint.
// { extraTokenParams: { electedCustomer: "customer123" } }
// This parameter can also be provided as parameter to the createOidc
// function. See: https://github.com/keycloakify/oidc-spa/blob/59b8db7db0b47c84e8f383a86677e88e884887cb/src/oidc.ts#L153-L163
);
}
// Subscribing to token renewal
prOidc.then(oidc => {
if( !oidc.isUserLoggedIn ){
return;
}
const { unsubscribe } = oidc.subscribeToTokensChange(tokens => {
console.log("Token Renewed", tokens);
});
setTimeout(() => {
// Call unsubscribe when you want to stop watching tokens change
unsubscribe();
}, 10_000);
});Inside of a React Component (not valid for real world usecase, just for diagnostic)
import { useState, useEffect } from "react";
import { assert } from "tsafe/assert";
import { useOidc, getOidc } from "../oidc";
import { decodeJwt } from "oidc-spa/tools/decodeJwt";
export function LogTokens() {
const { decodedIdToken, renewTokens } = useOidc({ assert: "user logged in" });
const { decodedAccessToken } = useDecodedAccessToken();
if (decodedAccessToken === undefined) {
// Loading...
return null;
}
return (
<>
<h3>Decoded ID Token:</h3>
<pre>{JSON.stringify(decodedIdToken, null, 2)}</pre>
<h3>Decoded Access Token:</h3>
<pre>{JSON.stringify(decodedAccessToken, null, 2)}</pre>
<br />
<button onClick={() => renewTokens()}>Refresh Tokens</button>
</>
);
}
function useDecodedAccessToken() {
const [decodedAccessToken, setDecodedAccessToken] = useState<
Record<string, unknown> | undefined /* Loading */
>(undefined);
useEffect(() => {
let cleanup: (() => void) | undefined = undefined;
let isActive = true;
(async () => {
const oidc = await getOidc();
if (!isActive) {
return;
}
assert(oidc.isUserLoggedIn);
const update = (accessToken: string) => setDecodedAccessToken(decodeJwt(accessToken));
const { unsubscribe } = oidc.subscribeToTokensChange(tokens => update(tokens.accessToken));
cleanup = () => {
unsubscribe();
};
{
const { accessToken } = await oidc.getTokens();
if (!isActive) {
return;
}
update(accessToken);
}
})();
return () => {
isActive = false;
cleanup?.();
};
}, []);
return { decodedAccessToken };
}
Last updated
Was this helpful?