@sourceregistry/sveltekit-oidc 1.6.9 → 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/README.md +2 -1
- package/dist/client/OIDCContext.svelte +33 -20
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +29 -17
- package/dist/server/jwt.d.ts +1 -1
- package/dist/server/jwt.js +2 -2
- package/dist/server/session.d.ts +1 -0
- package/dist/server/session.js +10 -0
- package/dist/server/types.d.ts +10 -0
- package/dist/server/utils.d.ts +2 -0
- package/dist/server/utils.js +19 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -298,8 +298,9 @@ Set these environment variables to enable it:
|
|
|
298
298
|
- `cookieSecret` should be a strong random secret and must stay stable across instances.
|
|
299
299
|
- Built-in `returnTo` and logout redirect values are restricted to same-origin paths. Use your own callback `onsuccess` logic if you need custom redirect policy.
|
|
300
300
|
- `clockSkewSeconds` defaults to `30` and tolerates small clock drift between your app and the identity provider.
|
|
301
|
+
- Local browser sessions expire after 8 hours by default (`sessionMaxAgeSeconds`). They also end when an unrefreshable access token expires; set a shorter value for higher-risk applications.
|
|
301
302
|
- `createInMemoryBackChannelLogoutStore()` is suitable for local development or single-instance deployments. Use Redis, SQL, or another shared store for production.
|
|
302
|
-
- The library validates `id_token` and `logout_token` values through `@sourceregistry/node-jwt` and provider JWKS metadata.
|
|
303
|
+
- The library validates `id_token` and `logout_token` values through `@sourceregistry/node-jwt` and provider JWKS metadata. ID tokens must contain `exp`, `iat`, and a matching nonce; UserInfo subjects must match the validated ID token.
|
|
303
304
|
- `groups` are normalized onto the session from `groups` and `roles` claims when present.
|
|
304
305
|
- Use `transformClaims`, `transformUser`, and `transformSession` to project provider-specific claims into your own session shape.
|
|
305
306
|
- `check_session_iframe` monitoring only runs when `monitorSession` is enabled, the provider advertises that endpoint, and the session includes `session_state`.
|
|
@@ -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
|
@@ -3,10 +3,10 @@ import { randomBytes } from 'node:crypto';
|
|
|
3
3
|
import { decode, fromWeb, verify } from '@sourceregistry/node-jwt/promises';
|
|
4
4
|
import { createOIDCCookieStore } from './cookies.js';
|
|
5
5
|
import { asAuthorizationHeader, createClientSecretJwtAssertion, createPrivateKeyJwtAssertion, fetchJson } from './jwt.js';
|
|
6
|
-
import { normalizeTokens, shouldRefresh } from './session.js';
|
|
7
|
-
import { absoluteUrl, base64UrlEncode, buildCookieOptions, collectGroups, createPKCEPair, internalRedirectPath, normalizeIssuer, normalizeScope, parseProviderError, toPublicSession } from './utils.js';
|
|
8
|
-
export { createInMemoryBackChannelLogoutStore, createInMemorySessionStore } from './store.js';
|
|
6
|
+
import { isSessionExpired, normalizeTokens, shouldRefresh } from './session.js';
|
|
7
|
+
import { absoluteUrl, base64UrlEncode, buildCookieOptions, collectGroups, createPKCEPair, internalRedirectPath, normalizeIssuer, normalizeScope, parseProviderError, toPublicSession, validateIdTokenClaims, validateUserInfoSubject } from './utils.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
|
};
|
|
@@ -38,12 +38,17 @@ export function createOIDC(options) {
|
|
|
38
38
|
const cookieOptions = buildCookieOptions(options.cookieOptions);
|
|
39
39
|
const clockSkewSeconds = options.clockSkewSeconds ?? 30;
|
|
40
40
|
const refreshToleranceSeconds = options.refreshToleranceSeconds ?? 30;
|
|
41
|
+
const sessionMaxAgeSeconds = options.sessionMaxAgeSeconds ?? 60 * 60 * 8;
|
|
42
|
+
if (!Number.isFinite(sessionMaxAgeSeconds) || sessionMaxAgeSeconds <= 0) {
|
|
43
|
+
throw new TypeError('sessionMaxAgeSeconds must be a positive finite number');
|
|
44
|
+
}
|
|
41
45
|
const sessionCookieName = options.sessionCookieName ?? 'oidc_session';
|
|
42
46
|
const stateCookieName = options.stateCookieName ?? 'oidc_auth_state';
|
|
43
47
|
const defaultScope = normalizeScope(options.scope);
|
|
44
48
|
const loginPath = options.loginPath ?? '/auth/login';
|
|
45
49
|
const redirectPath = options.redirectPath ?? '/auth/callback';
|
|
46
50
|
const clientAuthMethod = options.clientAuthMethod ?? (options.clientSecret ? 'client_secret_basic' : 'none');
|
|
51
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
47
52
|
const cookieStore = createOIDCCookieStore(options.cookieSecret, sessionCookieName, stateCookieName, cookieOptions);
|
|
48
53
|
let metadataPromise;
|
|
49
54
|
let jwksPromise;
|
|
@@ -101,7 +106,7 @@ export function createOIDC(options) {
|
|
|
101
106
|
if (!discoveryUrl) {
|
|
102
107
|
throw error(500, { message: 'OIDC issuer or discoveryUrl must be configured' });
|
|
103
108
|
}
|
|
104
|
-
const document = await fetchJson(discoveryUrl);
|
|
109
|
+
const document = await fetchJson(discoveryUrl, undefined, fetchImpl);
|
|
105
110
|
return {
|
|
106
111
|
...document,
|
|
107
112
|
...options.endpoints,
|
|
@@ -117,7 +122,7 @@ export function createOIDC(options) {
|
|
|
117
122
|
if (!metadata.jwks_uri) {
|
|
118
123
|
throw error(500, { message: 'OIDC jwks_uri is required to validate id_token values' });
|
|
119
124
|
}
|
|
120
|
-
return fromWeb(metadata.jwks_uri, { overrideEndpointCheck: true });
|
|
125
|
+
return fromWeb(metadata.jwks_uri, { overrideEndpointCheck: true, fetch: fetchImpl });
|
|
121
126
|
});
|
|
122
127
|
}
|
|
123
128
|
return jwksPromise;
|
|
@@ -206,7 +211,7 @@ export function createOIDC(options) {
|
|
|
206
211
|
method: 'POST',
|
|
207
212
|
headers: auth.headers,
|
|
208
213
|
body: auth.body
|
|
209
|
-
});
|
|
214
|
+
}, fetchImpl);
|
|
210
215
|
}
|
|
211
216
|
async function refreshTokens(refreshToken) {
|
|
212
217
|
const metadata = await getMetadata();
|
|
@@ -217,7 +222,7 @@ export function createOIDC(options) {
|
|
|
217
222
|
method: 'POST',
|
|
218
223
|
headers: auth.headers,
|
|
219
224
|
body: auth.body
|
|
220
|
-
});
|
|
225
|
+
}, fetchImpl);
|
|
221
226
|
}
|
|
222
227
|
async function validateIdToken(idToken, nonce) {
|
|
223
228
|
const metadata = await getMetadata();
|
|
@@ -227,16 +232,10 @@ export function createOIDC(options) {
|
|
|
227
232
|
algorithms: metadata.id_token_signing_alg_values_supported,
|
|
228
233
|
clockSkew: clockSkewSeconds
|
|
229
234
|
});
|
|
230
|
-
|
|
235
|
+
validateIdTokenClaims(claims, nonce);
|
|
236
|
+
return options.transformClaims
|
|
231
237
|
? await options.transformClaims(claims)
|
|
232
238
|
: claims;
|
|
233
|
-
if (transformedClaims.nonce !== nonce) {
|
|
234
|
-
throw error(401, { message: 'Invalid id_token nonce' });
|
|
235
|
-
}
|
|
236
|
-
if (!transformedClaims.sub) {
|
|
237
|
-
throw error(401, { message: 'id_token subject is required' });
|
|
238
|
-
}
|
|
239
|
-
return transformedClaims;
|
|
240
239
|
}
|
|
241
240
|
async function validateBackChannelLogoutToken(logoutToken) {
|
|
242
241
|
const metadata = await getMetadata();
|
|
@@ -265,7 +264,7 @@ export function createOIDC(options) {
|
|
|
265
264
|
headers: {
|
|
266
265
|
authorization: `Bearer ${accessToken}`
|
|
267
266
|
}
|
|
268
|
-
});
|
|
267
|
+
}, fetchImpl);
|
|
269
268
|
}
|
|
270
269
|
async function isRevoked(session) {
|
|
271
270
|
if (!session || !backChannelLogoutStore) {
|
|
@@ -278,6 +277,10 @@ export function createOIDC(options) {
|
|
|
278
277
|
if (!session) {
|
|
279
278
|
return null;
|
|
280
279
|
}
|
|
280
|
+
if (isSessionExpired(session, sessionMaxAgeSeconds)) {
|
|
281
|
+
await clearPersistedSession(cookies, persisted?.id);
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
281
284
|
if (await isRevoked(session)) {
|
|
282
285
|
await clearPersistedSession(cookies, persisted?.id);
|
|
283
286
|
return null;
|
|
@@ -291,6 +294,9 @@ export function createOIDC(options) {
|
|
|
291
294
|
? await validateIdToken(tokenResponse.id_token, session.nonce)
|
|
292
295
|
: session.claims;
|
|
293
296
|
const rawUser = options.fetchUserInfo !== false ? await fetchUserInfo(tokenResponse.access_token) : session.user;
|
|
297
|
+
if (claims) {
|
|
298
|
+
validateUserInfoSubject(claims, rawUser);
|
|
299
|
+
}
|
|
294
300
|
const user = options.transformUser
|
|
295
301
|
? await options.transformUser(rawUser, { claims })
|
|
296
302
|
: rawUser;
|
|
@@ -385,6 +391,7 @@ export function createOIDC(options) {
|
|
|
385
391
|
const rawUser = options.fetchUserInfo === false
|
|
386
392
|
? undefined
|
|
387
393
|
: await fetchUserInfo(tokenResponse.access_token).catch(() => undefined);
|
|
394
|
+
validateUserInfoSubject(claims, rawUser);
|
|
388
395
|
const user = options.transformUser
|
|
389
396
|
? await options.transformUser(rawUser, { claims })
|
|
390
397
|
: rawUser;
|
|
@@ -526,9 +533,14 @@ export function createOIDC(options) {
|
|
|
526
533
|
if (event.request.method !== 'POST') {
|
|
527
534
|
throw error(405, { message: 'Logout requires POST' });
|
|
528
535
|
}
|
|
529
|
-
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;
|
|
530
540
|
const clearSessionOnly = event.url.searchParams.get('clearSessionOnly') === '1' ||
|
|
531
541
|
event.url.searchParams.get('clearSessionOnly') === 'true' ||
|
|
542
|
+
form?.get('clearSessionOnly')?.toString() === '1' ||
|
|
543
|
+
form?.get('clearSessionOnly')?.toString() === 'true' ||
|
|
532
544
|
defaults.clearSessionOnly;
|
|
533
545
|
return signOut(event, { ...defaults, postLogoutRedirectUri, clearSessionOnly });
|
|
534
546
|
};
|
package/dist/server/jwt.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { OIDCClientAssertionOptions, OIDCClientSecretJwtOptions, OIDCPrivateKeyJwtOptions } from './types.js';
|
|
2
|
-
export declare function fetchJson<T>(url: string, init?: RequestInit): Promise<T>;
|
|
2
|
+
export declare function fetchJson<T>(url: string, init?: RequestInit, fetchImpl?: typeof fetch): Promise<T>;
|
|
3
3
|
export declare function asAuthorizationHeader(clientId: string, clientSecret: string): string;
|
|
4
4
|
export declare function createClientSecretJwtAssertion(options: OIDCClientAssertionOptions & OIDCClientSecretJwtOptions): Promise<string>;
|
|
5
5
|
export declare function createPrivateKeyJwtAssertion(options: OIDCClientAssertionOptions & OIDCPrivateKeyJwtOptions): Promise<string>;
|
package/dist/server/jwt.js
CHANGED
|
@@ -2,8 +2,8 @@ import { error } from '@sveltejs/kit';
|
|
|
2
2
|
import { randomBytes } from 'node:crypto';
|
|
3
3
|
import { sign } from '@sourceregistry/node-jwt/promises';
|
|
4
4
|
import { base64UrlEncode } from './utils.js';
|
|
5
|
-
export async function fetchJson(url, init) {
|
|
6
|
-
const response = await
|
|
5
|
+
export async function fetchJson(url, init, fetchImpl = fetch) {
|
|
6
|
+
const response = await fetchImpl(url, init);
|
|
7
7
|
if (!response.ok) {
|
|
8
8
|
const body = await response.text().catch(() => '');
|
|
9
9
|
throw error(response.status, {
|
package/dist/server/session.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { OIDCSession, OIDCSessionTokens, OIDCTokenResponse, OIDCUserClaims } from './types.js';
|
|
2
2
|
export declare function normalizeTokens(tokenResponse: OIDCTokenResponse, defaultScope: string[], existing?: OIDCSessionTokens, now?: number): OIDCSessionTokens;
|
|
3
3
|
export declare function shouldRefresh<TClaims extends OIDCUserClaims = OIDCUserClaims>(session: OIDCSession<TClaims>, refreshToleranceSeconds: number, now?: number): boolean;
|
|
4
|
+
export declare function isSessionExpired<TClaims extends OIDCUserClaims = OIDCUserClaims>(session: OIDCSession<TClaims>, sessionMaxAgeSeconds: number, now?: number): boolean;
|
package/dist/server/session.js
CHANGED
|
@@ -17,3 +17,13 @@ export function shouldRefresh(session, refreshToleranceSeconds, now = Math.floor
|
|
|
17
17
|
}
|
|
18
18
|
return session.tokens.expiresAt - refreshToleranceSeconds <= now;
|
|
19
19
|
}
|
|
20
|
+
export function isSessionExpired(session, sessionMaxAgeSeconds, now = Math.floor(Date.now() / 1000)) {
|
|
21
|
+
if (session.createdAt + sessionMaxAgeSeconds <= now) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
// Without a refresh token, an expired access token cannot establish that
|
|
25
|
+
// the user's session is still valid. Do not keep the local session alive.
|
|
26
|
+
return !session.tokens.refreshToken &&
|
|
27
|
+
session.tokens.expiresAt !== undefined &&
|
|
28
|
+
session.tokens.expiresAt <= now;
|
|
29
|
+
}
|
package/dist/server/types.d.ts
CHANGED
|
@@ -53,6 +53,7 @@ export type OIDCUserClaims = Record<string, unknown> & {
|
|
|
53
53
|
iss?: string;
|
|
54
54
|
aud?: string | string[];
|
|
55
55
|
exp?: number;
|
|
56
|
+
iat?: number;
|
|
56
57
|
nbf?: number;
|
|
57
58
|
nonce?: string;
|
|
58
59
|
};
|
|
@@ -159,6 +160,8 @@ export type OIDCOptions<TClaims extends OIDCUserClaims = OIDCUserClaims, TSessio
|
|
|
159
160
|
cookieOptions?: Partial<CookieOptions>;
|
|
160
161
|
clockSkewSeconds?: number;
|
|
161
162
|
refreshToleranceSeconds?: number;
|
|
163
|
+
/** Maximum lifetime of a local browser session. Defaults to 8 hours. */
|
|
164
|
+
sessionMaxAgeSeconds?: number;
|
|
162
165
|
defaultLoginRedirect?: string;
|
|
163
166
|
defaultLogoutRedirect?: string;
|
|
164
167
|
sessionStore?: OIDCSessionStore<TClaims, TSession> | 'memory';
|
|
@@ -176,6 +179,13 @@ export type OIDCOptions<TClaims extends OIDCUserClaims = OIDCUserClaims, TSessio
|
|
|
176
179
|
}) => MaybePromise<TSession>;
|
|
177
180
|
endpoints?: Partial<OIDCDiscoveryDocument>;
|
|
178
181
|
logger?: OIDCLogger | false;
|
|
182
|
+
/**
|
|
183
|
+
* Custom fetch implementation used for all OIDC network calls
|
|
184
|
+
* (discovery, token, userinfo, JWKS). Useful in dev to work around
|
|
185
|
+
* self-signed certs via a custom https.Agent — do not disable
|
|
186
|
+
* TLS verification in production.
|
|
187
|
+
*/
|
|
188
|
+
fetch?: typeof fetch;
|
|
179
189
|
};
|
|
180
190
|
export type OIDCLoginOptions = {
|
|
181
191
|
returnTo?: string;
|
package/dist/server/utils.d.ts
CHANGED
|
@@ -22,4 +22,6 @@ export declare function absoluteUrl(event: {
|
|
|
22
22
|
export declare function internalRedirectPath(event: {
|
|
23
23
|
url: URL;
|
|
24
24
|
}, pathOrUrl: string | undefined, fallback?: string): string;
|
|
25
|
+
export declare function validateIdTokenClaims(claims: OIDCUserClaims, nonce: string): void;
|
|
26
|
+
export declare function validateUserInfoSubject(claims: OIDCUserClaims, user: OIDCUserClaims | undefined): void;
|
|
25
27
|
export declare function toPublicSession<TClaims extends OIDCUserClaims = OIDCUserClaims>(session: OIDCSession<TClaims> | null): OIDCPublicSession<TClaims> | null;
|
package/dist/server/utils.js
CHANGED
|
@@ -119,6 +119,25 @@ export function internalRedirectPath(event, pathOrUrl, fallback = '/') {
|
|
|
119
119
|
return fallback;
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
|
+
export function validateIdTokenClaims(claims, nonce) {
|
|
123
|
+
if (!Number.isFinite(claims.exp)) {
|
|
124
|
+
throw error(401, { message: 'id_token expiration is required' });
|
|
125
|
+
}
|
|
126
|
+
if (!Number.isFinite(claims.iat)) {
|
|
127
|
+
throw error(401, { message: 'id_token issued-at time is required' });
|
|
128
|
+
}
|
|
129
|
+
if (claims.nonce !== nonce) {
|
|
130
|
+
throw error(401, { message: 'Invalid id_token nonce' });
|
|
131
|
+
}
|
|
132
|
+
if (!claims.sub) {
|
|
133
|
+
throw error(401, { message: 'id_token subject is required' });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
export function validateUserInfoSubject(claims, user) {
|
|
137
|
+
if (user && user.sub !== claims.sub) {
|
|
138
|
+
throw error(401, { message: 'UserInfo subject does not match id_token subject' });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
122
141
|
export function toPublicSession(session) {
|
|
123
142
|
if (!session)
|
|
124
143
|
return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sourceregistry/sveltekit-oidc",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.11",
|
|
4
4
|
"description": "OIDC authentication helpers for SvelteKit applications",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"scripts": {
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"oauth"
|
|
85
85
|
],
|
|
86
86
|
"dependencies": {
|
|
87
|
-
"@sourceregistry/node-jwt": "^1.5.
|
|
87
|
+
"@sourceregistry/node-jwt": "^1.5.11"
|
|
88
88
|
},
|
|
89
89
|
"release": {
|
|
90
90
|
"branches": [
|