@sourceregistry/sveltekit-oidc 1.6.10 → 1.6.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/OIDCContext.svelte +33 -20
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +8 -4
- package/package.json +1 -1
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
let status = $state<'authenticated' | 'unauthenticated' | 'expired' | 'revoked'>('unauthenticated');
|
|
47
47
|
let revalidating = $state(false);
|
|
48
48
|
let handledUnauthenticated = $state(false);
|
|
49
|
+
let sessionExpiredDuringRevalidation = false;
|
|
49
50
|
|
|
50
51
|
const metadata = $derived(config.metadata);
|
|
51
52
|
const resolvedLoginPath = $derived(loginPath ?? config.loginPath ?? '/auth/login');
|
|
@@ -88,23 +89,43 @@
|
|
|
88
89
|
|
|
89
90
|
void context;
|
|
90
91
|
|
|
92
|
+
// SvelteKit navigation hooks are registered for the component lifetime.
|
|
93
|
+
// Only intercept login redirects while a background revalidation is active.
|
|
94
|
+
beforeNavigate(({to, cancel}) => {
|
|
95
|
+
if (revalidating && to?.url.pathname.startsWith(resolvedLoginPath)) {
|
|
96
|
+
cancel();
|
|
97
|
+
sessionExpiredDuringRevalidation = true;
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
91
101
|
function buildLoginUrl(returnTo = `${window.location.pathname}${window.location.search}`) {
|
|
92
102
|
return `${resolvedLoginPath}?returnTo=${encodeURIComponent(returnTo)}`;
|
|
93
103
|
}
|
|
94
104
|
|
|
95
105
|
async function logout(clearSessionOnly = false) {
|
|
96
|
-
const body = new URLSearchParams();
|
|
97
106
|
if (clearSessionOnly) {
|
|
98
|
-
|
|
107
|
+
// Session-monitor events must clear only this application's session.
|
|
108
|
+
// Keep the flag in the URL because logoutHandler also supports callers
|
|
109
|
+
// that do not send a form body.
|
|
110
|
+
const url = new URL(logoutPath, window.location.href);
|
|
111
|
+
url.searchParams.set('clearSessionOnly', '1');
|
|
112
|
+
|
|
113
|
+
await fetch(url, {
|
|
114
|
+
method: 'POST',
|
|
115
|
+
redirect: 'manual'
|
|
116
|
+
});
|
|
117
|
+
return;
|
|
99
118
|
}
|
|
100
119
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
120
|
+
// Provider logout can include an interactive confirmation and redirects.
|
|
121
|
+
// A fetch would follow that flow in the background, leaving the provider
|
|
122
|
+
// session intact and allowing the app to immediately sign in again.
|
|
123
|
+
const form = document.createElement('form');
|
|
124
|
+
form.method = 'POST';
|
|
125
|
+
form.action = logoutPath;
|
|
126
|
+
form.style.display = 'none';
|
|
127
|
+
document.body.append(form);
|
|
128
|
+
form.submit();
|
|
108
129
|
}
|
|
109
130
|
|
|
110
131
|
function login(returnTo?: string) {
|
|
@@ -118,21 +139,13 @@
|
|
|
118
139
|
revalidating = true;
|
|
119
140
|
|
|
120
141
|
// If the server redirects to the login path during a background
|
|
121
|
-
// revalidation (e.g. session lost, HMR store reset),
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
let sessionExpiredDuringRevalidation = false;
|
|
125
|
-
const stopIntercept = beforeNavigate(({ to, cancel }) => {
|
|
126
|
-
if (to?.url.pathname.startsWith(resolvedLoginPath)) {
|
|
127
|
-
cancel();
|
|
128
|
-
sessionExpiredDuringRevalidation = true;
|
|
129
|
-
}
|
|
130
|
-
});
|
|
142
|
+
// revalidation (e.g. session lost, HMR store reset), the component's
|
|
143
|
+
// navigation hook records it so we can handle the redirect below.
|
|
144
|
+
sessionExpiredDuringRevalidation = false;
|
|
131
145
|
|
|
132
146
|
try {
|
|
133
147
|
await invalidateAll();
|
|
134
148
|
} finally {
|
|
135
|
-
stopIntercept();
|
|
136
149
|
revalidating = false;
|
|
137
150
|
}
|
|
138
151
|
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { OIDCInstance, OIDCOptions, OIDCSession, OIDCUserClaims } from './types.js';
|
|
2
2
|
export type * from './types.js';
|
|
3
3
|
export { createInMemoryBackChannelLogoutStore, createInMemorySessionStore } from './store.js';
|
|
4
4
|
export declare function createOIDC<TClaims extends OIDCUserClaims = OIDCUserClaims, TSession extends OIDCSession<TClaims> = OIDCSession<TClaims>>(options: OIDCOptions<TClaims, TSession>): OIDCInstance<TClaims, TSession>;
|
package/dist/server/index.js
CHANGED
|
@@ -5,8 +5,8 @@ import { createOIDCCookieStore } from './cookies.js';
|
|
|
5
5
|
import { asAuthorizationHeader, createClientSecretJwtAssertion, createPrivateKeyJwtAssertion, fetchJson } from './jwt.js';
|
|
6
6
|
import { isSessionExpired, normalizeTokens, shouldRefresh } from './session.js';
|
|
7
7
|
import { absoluteUrl, base64UrlEncode, buildCookieOptions, collectGroups, createPKCEPair, internalRedirectPath, normalizeIssuer, normalizeScope, parseProviderError, toPublicSession, validateIdTokenClaims, validateUserInfoSubject } from './utils.js';
|
|
8
|
-
export { createInMemoryBackChannelLogoutStore, createInMemorySessionStore } from './store.js';
|
|
9
8
|
import { createInMemoryBackChannelLogoutStore, createInMemorySessionStore } from './store.js';
|
|
9
|
+
export { createInMemoryBackChannelLogoutStore, createInMemorySessionStore } from './store.js';
|
|
10
10
|
function buildLogger(logger) {
|
|
11
11
|
const noop = () => {
|
|
12
12
|
};
|
|
@@ -233,10 +233,9 @@ export function createOIDC(options) {
|
|
|
233
233
|
clockSkew: clockSkewSeconds
|
|
234
234
|
});
|
|
235
235
|
validateIdTokenClaims(claims, nonce);
|
|
236
|
-
|
|
236
|
+
return options.transformClaims
|
|
237
237
|
? await options.transformClaims(claims)
|
|
238
238
|
: claims;
|
|
239
|
-
return transformedClaims;
|
|
240
239
|
}
|
|
241
240
|
async function validateBackChannelLogoutToken(logoutToken) {
|
|
242
241
|
const metadata = await getMetadata();
|
|
@@ -534,9 +533,14 @@ export function createOIDC(options) {
|
|
|
534
533
|
if (event.request.method !== 'POST') {
|
|
535
534
|
throw error(405, { message: 'Logout requires POST' });
|
|
536
535
|
}
|
|
537
|
-
const
|
|
536
|
+
const form = await event.request.formData().catch(() => null);
|
|
537
|
+
const postLogoutRedirectUri = event.url.searchParams.get('postLogoutRedirectUri') ??
|
|
538
|
+
form?.get('postLogoutRedirectUri')?.toString() ??
|
|
539
|
+
defaults.postLogoutRedirectUri;
|
|
538
540
|
const clearSessionOnly = event.url.searchParams.get('clearSessionOnly') === '1' ||
|
|
539
541
|
event.url.searchParams.get('clearSessionOnly') === 'true' ||
|
|
542
|
+
form?.get('clearSessionOnly')?.toString() === '1' ||
|
|
543
|
+
form?.get('clearSessionOnly')?.toString() === 'true' ||
|
|
540
544
|
defaults.clearSessionOnly;
|
|
541
545
|
return signOut(event, { ...defaults, postLogoutRedirectUri, clearSessionOnly });
|
|
542
546
|
};
|