Callbacks & URL cleanup
What happens on startup
Once per context (plugin creation or AuthProvider mount), in the browser, the library runs the same initialization sequence as react-oidc-context:
- If the URL carries an OIDC authorization response (
?code=…&state=…or?error=…&state=…, query or fragment) andskipSigninCallbackis not set:userManager.signinCallback()is awaited, then youronSigninCallback(user). - Otherwise the stored session is looked up with
userManager.getUser(). useris committed (nullif none),isLoadingflips tofalse. On failure,erroris set withsource: "signinCallback".- Independently, if
matchSignoutCallback(settings)returnstrue:userManager.signoutCallback()is awaited, then youronSignoutCallback(resp). auth.initializedresolves — it never rejects; failures surface onerror.
The full contract lives in SPEC §5.
onSigninCallback — cleaning the URL
The library deliberately does not remove ?code&state from the address bar (parity with react-oidc-context) — that's your onSigninCallback:
onSigninCallback: (user) => {
const returnTo =
(user?.state as { returnTo?: string } | undefined)?.returnTo ?? "/";
// Not awaited: a guard awaiting auth.initialized would deadlock otherwise.
void router.replace(returnTo);
},onSigninCallback: () => {
window.history.replaceState({}, document.title, window.location.pathname);
},See Protecting routes for why the vue-router variant must not be awaited and why replaceState alone doesn't work there.
skipSigninCallback — foreign auth params
If a page in your app receives ?code&state that belong to a different OAuth integration, initialization would try to process them and fail. Skip it for those URLs:
createOidcAuth({
// ...
skipSigninCallback: window.location.pathname === "/stripe-connect-callback",
});The value is read once, when the context is created (i.e. per full page load). The stored session is still restored via getUser(); the URL is left untouched.
matchSignoutCallback / onSignoutCallback
If your post_logout_redirect_uri points back into the app and you need to process the signout response (e.g. to read state passed to signoutRedirect):
createOidcAuth({
// ...
post_logout_redirect_uri: `${window.location.origin}/signed-out`,
matchSignoutCallback: (settings) =>
window.location.href.startsWith(settings.post_logout_redirect_uri!),
onSignoutCallback: (resp) => {
window.history.replaceState({}, document.title, "/");
},
});onRemoveUser
Invoked after auth.removeUser() completes — e.g. to clear app state alongside the local session:
createOidcAuth({
// ...
onRemoveUser: () => {
pinia.state.value = {};
},
});removeUser() only clears the local session; it does not end the IdP session (use signoutRedirect for that).
Errors
All failures funnel into the error ref as an ErrorContext — an Error tagged with the operation that produced it:
type ErrorSource =
| "signinCallback"
| "signoutCallback"
| "renewSilent"
| "signinRedirect"
| "signinPopup"
| "signinSilent"
| "signinResourceOwnerCredentials"
| "signoutRedirect"
| "signoutPopup"
| "signoutSilent"
| "unknown";
type ErrorContext = Error & {
source: ErrorSource;
/** Original thrown value when it was not an Error instance. */
innerError?: unknown;
};- Initialization failures set
source: "signinCallback"/"signoutCallback". - Silent-renew failures (from the
UserManagerEventsbus) setsource: "renewSilent". - Navigator methods (
signinRedirect(), …) set their own name assourceand still reject, so imperative callers cantry/catchwhile templates render the ref. errorclears on the next successful user load.
<template>
<p v-if="error">{{ error.source }}: {{ error.message }}</p>
</template>