OIDC authentication helpers for SvelteKit with:
none, client_secret_basic, client_secret_post, client_secret_jwt, and private_key_jwthandle hook for attaching auth state to event.localsOIDCContext provider for client-side auth state and session lifecycle handlingnpm install sveltekit-oidc
// src/lib/server/auth.ts
import {
createInMemoryBackChannelLogoutStore,
createOIDC
} from 'sveltekit-oidc/server';
export const oidc = createOIDC({
issuer: 'https://your-idp.example.com',
clientId: process.env.OIDC_CLIENT_ID!,
clientSecret: process.env.OIDC_CLIENT_SECRET!,
cookieSecret: process.env.OIDC_COOKIE_SECRET!,
clientAuthMethod: 'client_secret_basic',
loginPath: '/auth/login',
redirectPath: '/auth/callback',
scope: ['openid', 'profile', 'email', 'offline_access'],
clockSkewSeconds: 30,
fetchUserInfo: true,
backChannelLogoutStore: createInMemoryBackChannelLogoutStore(),
transformSession(session) {
return {
...session,
groups: session.groups,
user: session.user
? {
...session.user,
groups: session.groups
}
: session.user
};
},
cookieOptions: {
secure: process.env.NODE_ENV === 'production'
}
});
// src/hooks.server.ts
import { oidc } from '$lib/server/auth';
export const handle = oidc.handle;
// src/routes/auth/login/+server.ts
import { oidc } from '$lib/server/auth';
export const GET = oidc.loginHandler();
// src/routes/auth/callback/+server.ts
import { oidc } from '$lib/server/auth';
export const GET = oidc.callbackHandler({
redirectTo: '/'
});
// src/routes/auth/logout/+server.ts
import { oidc } from '$lib/server/auth';
export const GET = oidc.logoutHandler();
export const POST = oidc.logoutHandler();
// src/routes/auth/backchannel-logout/+server.ts
import { oidc } from '$lib/server/auth';
export const POST = oidc.backChannelLogoutHandler();
If you prefer form actions instead of dedicated routes:
// src/routes/+page.server.ts
import { oidc } from '$lib/server/auth';
export const actions = oidc.createActions();
// src/routes/+layout.server.ts
import { oidc } from '$lib/server/auth';
export async function load(event) {
return {
session: await oidc.getPublicSession(event),
sessionManagement: await oidc.getSessionManagementConfig()
};
}
<script lang="ts">
import { OIDCContext } from 'sveltekit-oidc';
let { data } = $props();
</script>
<OIDCContext
session={data.session}
config={data.sessionManagement}
logoutPath="/auth/logout"
redirectIfUnauthenticated={false}
>
<Account />
</OIDCContext>
<!-- src/lib/Account.svelte -->
<script lang="ts">
import { useOIDC } from 'sveltekit-oidc';
const oidc = useOIDC();
</script>
{#if oidc.isAuthenticated}
<p>Signed in as {oidc.user?.email ?? oidc.user?.name ?? oidc.session?.sub}</p>
<form method="POST" action="/auth/logout">
<button type="submit">Sign out</button>
</form>
{:else}
<a href="/auth/login?returnTo=%2Faccount">Sign in</a>
{/if}
OIDCContext handles:
check_session_iframe polling when the provider advertises itinvalidateAll() revalidation so revoked server sessions are detecteduseOIDC() / getOIDCContext()This repository now includes a runnable example under src/routes and src/hooks.server.ts.
Set these environment variables to enable it:
OIDC_ISSUEROIDC_CLIENT_IDOIDC_COOKIE_SECRETOIDC_CLIENT_SECRETOIDC_SCOPEOIDC_POST_LOGOUT_REDIRECT_URIcookieSecret should be a strong random secret and must stay stable across instances.clockSkewSeconds defaults to 30 and tolerates small clock drift between your app and the identity provider.createInMemoryBackChannelLogoutStore() is suitable for local development or single-instance deployments. Use Redis, SQL, or another shared store for production.id_token and logout_token values through @sourceregistry/node-jwt and provider JWKS metadata.groups are normalized onto the session from groups and roles claims when present.transformClaims, transformUser, and transformSession to project provider-specific claims into your own session shape.check_session_iframe monitoring only runs when the provider advertises that endpoint and the session includes session_state.event.locals.oidc is attached by the hook, but you should add your own app.d.ts augmentation in the consuming app for full typing.