@absolutejs/auth 0.57.6 → 0.57.8

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/index.js CHANGED
@@ -367,17 +367,23 @@ var providers = defineProviders({
367
367
  },
368
368
  apple: {
369
369
  authorizationUrl: "https://appleid.apple.com/auth/authorize",
370
+ createAuthorizationURLSearchParams: {
371
+ response_mode: "form_post"
372
+ },
373
+ createClientSecret: (config) => createAppleClientSecret(config),
370
374
  isOIDC: true,
371
375
  isRefreshable: true,
372
- PKCEMethod: "S256",
373
- profileRequest: {
374
- authIn: "header",
375
- encoding: "application/json",
376
- method: "GET",
377
- url: "https://appleid.apple.com/auth/userinfo"
376
+ revocationRequest: {
377
+ authIn: "body",
378
+ encoding: "application/x-www-form-urlencoded",
379
+ tokenParamName: "token",
380
+ url: "https://appleid.apple.com/auth/revoke"
378
381
  },
379
382
  scopeRequired: false,
380
- subject: ["id"],
383
+ subject: ["sub"],
384
+ subjectBySource: {
385
+ idToken: ["sub"]
386
+ },
381
387
  subjectType: "string",
382
388
  tokenRequest: {
383
389
  authIn: "body",
@@ -446,6 +452,7 @@ var providers = defineProviders({
446
452
  token_type_hint: "refresh_token"
447
453
  }),
448
454
  encoding: "application/json",
455
+ inputSource: "refreshToken",
449
456
  tokenParamName: "token",
450
457
  url: (config) => `https://${config.domain}/oauth/revoke`
451
458
  },
@@ -1577,6 +1584,7 @@ var providers = defineProviders({
1577
1584
  token_type_hint: "refresh_token"
1578
1585
  }),
1579
1586
  encoding: "application/json",
1587
+ inputSource: "refreshToken",
1580
1588
  url: "https://www.reddit.com/api/v1/revoke_token"
1581
1589
  },
1582
1590
  scopeRequired: true,
@@ -1950,49 +1958,27 @@ var providers = defineProviders({
1950
1958
  authorizationUrl: "https://account.withings.com/oauth2_user/authorize2",
1951
1959
  isOIDC: false,
1952
1960
  isRefreshable: true,
1953
- profileRequest: {
1954
- authIn: "header",
1955
- body: async (config) => {
1956
- const props = await getWithingsProps(config);
1957
- if (props === undefined)
1958
- throw new Error("Failed to get Withings search properties");
1959
- const { nonce, hashedSignature } = props;
1960
- return [
1961
- ["action", "getuser"],
1962
- ["nonce", nonce],
1963
- ["client_id", config.clientId],
1964
- ["signature", hashedSignature]
1965
- ];
1966
- },
1967
- encoding: "application/x-www-form-urlencoded",
1968
- method: "POST",
1969
- url: "https://wbsapi.withings.net/v2/oauth2"
1970
- },
1971
1961
  refreshAccessTokenBody: {
1972
1962
  action: "requesttoken"
1973
1963
  },
1974
1964
  revocationRequest: {
1975
- authIn: "header",
1976
- body: async (config) => {
1977
- const props = await getWithingsProps(config);
1978
- if (!props)
1979
- throw new Error("Failed to get Withings props");
1980
- const { nonce, hashedSignature } = props;
1981
- return [
1982
- ["action", "revoke"],
1983
- ["client_id", config.clientId],
1984
- ["nonce", nonce],
1985
- ["signature", hashedSignature]
1986
- ];
1987
- },
1965
+ authIn: "body",
1966
+ body: (config) => getWithingsSignatureParams(config, "revoke"),
1988
1967
  encoding: "application/x-www-form-urlencoded",
1989
- method: "POST",
1990
- url: "https://wbsapi.withings.net/v2/oauth2"
1968
+ includeClientCredentials: false,
1969
+ inputSource: "subject",
1970
+ inputType: "number",
1971
+ tokenParamName: "userid",
1972
+ url: "https://wbsapi.withings.net/v2/oauth2",
1973
+ validateResponse: (value) => assertWithingsSuccess(value)
1991
1974
  },
1992
1975
  scopeDelimiter: ",",
1993
1976
  scopeRequired: true,
1994
1977
  subject: ["userid"],
1995
- subjectType: "string",
1978
+ subjectBySource: {
1979
+ tokenResponse: ["body", "userid"]
1980
+ },
1981
+ subjectType: "number",
1996
1982
  tokenRequest: {
1997
1983
  authIn: "body",
1998
1984
  encoding: "application/x-www-form-urlencoded",
@@ -2184,14 +2170,39 @@ var isPKCEProviderOption = (option) => {
2184
2170
  const provider = providers[option];
2185
2171
  return provider.PKCEMethod !== undefined;
2186
2172
  };
2187
- var isRefreshableOAuth2Client = (providerName, _client) => isRefreshableProviderOption(providerName);
2173
+ function isProfileOAuth2Client(providerOrClient, maybeClient) {
2174
+ const client = maybeClient ?? providerOrClient;
2175
+ if (maybeClient !== undefined && (typeof providerOrClient !== "string" || !isProfileProviderOption(providerOrClient))) {
2176
+ return false;
2177
+ }
2178
+ return typeof client === "object" && client !== null && "fetchUserProfile" in client && typeof client.fetchUserProfile === "function";
2179
+ }
2180
+ var isProfileProviderOption = (option) => {
2181
+ if (!isValidProviderOption(option))
2182
+ return false;
2183
+ const provider = providers[option];
2184
+ return provider.profileRequest !== undefined;
2185
+ };
2186
+ function isRefreshableOAuth2Client(providerOrClient, maybeClient) {
2187
+ const client = maybeClient ?? providerOrClient;
2188
+ if (maybeClient !== undefined && (typeof providerOrClient !== "string" || !isRefreshableProviderOption(providerOrClient))) {
2189
+ return false;
2190
+ }
2191
+ return typeof client === "object" && client !== null && "refreshAccessToken" in client && typeof client.refreshAccessToken === "function";
2192
+ }
2188
2193
  var isRefreshableProviderOption = (option) => {
2189
2194
  if (!isValidProviderOption(option))
2190
2195
  return false;
2191
2196
  const provider = providers[option];
2192
2197
  return provider.isRefreshable;
2193
2198
  };
2194
- var isRevocableOAuth2Client = (providerName, _client) => isRevocableProviderOption(providerName);
2199
+ function isRevocableOAuth2Client(providerOrClient, maybeClient) {
2200
+ const client = maybeClient ?? providerOrClient;
2201
+ if (maybeClient !== undefined && (typeof providerOrClient !== "string" || !isRevocableProviderOption(providerOrClient))) {
2202
+ return false;
2203
+ }
2204
+ return typeof client === "object" && client !== null && "resolveRevocationInput" in client && typeof client.resolveRevocationInput === "function" && "revokeToken" in client && typeof client.revokeToken === "function";
2205
+ }
2195
2206
  var isRevocableProviderOption = (option) => {
2196
2207
  if (!isValidProviderOption(option))
2197
2208
  return false;
@@ -2205,6 +2216,14 @@ var isScopeRequiredProviderOption = (option) => {
2205
2216
  return provider.scopeRequired;
2206
2217
  };
2207
2218
  var isValidProviderOption = (option) => Object.hasOwn(providers, option);
2219
+ var readPath = (value, path) => path.reduce((cursor, key) => cursor && typeof cursor === "object" ? Reflect.get(cursor, key) : undefined, value);
2220
+ var assertWithingsSuccess = (value) => {
2221
+ if (!isObject(value) || value.status !== 0) {
2222
+ const status = isObject(value) ? value.status : "invalid response";
2223
+ const detail = isObject(value) && typeof value.error === "string" ? `: ${value.error}` : "";
2224
+ throw new Error(`Withings request failed (${String(status)})${detail}`);
2225
+ }
2226
+ };
2208
2227
  var createOAuth2FetchError = async (response) => {
2209
2228
  const clone = response.clone();
2210
2229
  const prefix = `HTTP ${response.status} ${response.statusText} for ${response.url}`;
@@ -2238,16 +2257,27 @@ var createOAuth2Request = ({
2238
2257
  }
2239
2258
  oauthHeaders.set("Authorization", `Basic ${encodeBase64(`${clientId}:${clientSecret}`)}`);
2240
2259
  }
2260
+ if (body === undefined && authIn !== "body") {
2261
+ return new Request(url, {
2262
+ headers: oauthHeaders,
2263
+ method: "POST"
2264
+ });
2265
+ }
2241
2266
  if (encoding === "application/json") {
2242
2267
  oauthHeaders.set("Content-Type", "application/json");
2268
+ const jsonBody = body instanceof URLSearchParams ? Object.fromEntries(body.entries()) : { ...body };
2269
+ if (authIn === "body")
2270
+ jsonBody.client_id = clientId;
2271
+ if (authIn === "body" && clientSecret)
2272
+ jsonBody.client_secret = clientSecret;
2243
2273
  return new Request(url, {
2244
- body: JSON.stringify(body),
2274
+ body: JSON.stringify(jsonBody),
2245
2275
  headers: oauthHeaders,
2246
2276
  method: "POST"
2247
2277
  });
2248
2278
  }
2249
2279
  oauthHeaders.set("Content-Type", "application/x-www-form-urlencoded");
2250
- const entries = body instanceof URLSearchParams ? Array.from(body.entries()) : Object.entries(body).filter((entry) => typeof entry[1] === "string");
2280
+ const entries = body instanceof URLSearchParams ? Array.from(body.entries()) : Object.entries(body ?? {}).filter((entry) => typeof entry[1] === "string");
2251
2281
  const params = new URLSearchParams(entries);
2252
2282
  if (authIn === "body") {
2253
2283
  params.set("client_id", clientId);
@@ -2293,25 +2323,31 @@ var encodeBase64 = (input) => {
2293
2323
  }
2294
2324
  return btoa(raw);
2295
2325
  };
2296
- var getWithingsProps = async (config) => {
2326
+ var getWithingsSignatureParams = async (config, action) => {
2297
2327
  const timestamp = Math.floor(Date.now() / 1000);
2298
- const signature = `getnonce,${config.clientId},${timestamp}`;
2299
- const hashedSignature = await hmacSha256(signature, config.clientSecret);
2328
+ const nonceSignature = await hmacSha256(`getnonce,${config.clientId},${timestamp}`, config.clientSecret);
2300
2329
  const nonceUrl = new URL("https://wbsapi.withings.net/v2/signature");
2301
2330
  nonceUrl.searchParams.set("action", "getnonce");
2302
2331
  nonceUrl.searchParams.set("client_id", config.clientId);
2303
2332
  nonceUrl.searchParams.set("timestamp", timestamp.toString());
2304
- nonceUrl.searchParams.set("signature", hashedSignature);
2333
+ nonceUrl.searchParams.set("signature", nonceSignature);
2305
2334
  const nonceTarget = nonceUrl.toString();
2306
2335
  const nonceResponse = await fetch(nonceTarget, { method: "POST" });
2336
+ if (!nonceResponse.ok) {
2337
+ throw await createOAuth2FetchError(nonceResponse);
2338
+ }
2307
2339
  const nonceData = await nonceResponse.json();
2308
- if (nonceData.status === 0) {
2309
- return {
2310
- hashedSignature,
2311
- nonce: nonceData.body.nonce
2312
- };
2340
+ if (!isObject(nonceData) || nonceData.status !== 0 || !isObject(nonceData.body) || typeof nonceData.body.nonce !== "string" || nonceData.body.nonce.length === 0) {
2341
+ throw new Error("Withings returned an invalid nonce response");
2313
2342
  }
2314
- return;
2343
+ const { nonce } = nonceData.body;
2344
+ const signature = await hmacSha256(`${action},${config.clientId},${nonce}`, config.clientSecret);
2345
+ return {
2346
+ action,
2347
+ client_id: config.clientId,
2348
+ nonce,
2349
+ signature
2350
+ };
2315
2351
  };
2316
2352
  var hmacSha256 = async (message, secret) => {
2317
2353
  const encoder = new TextEncoder;
@@ -2319,15 +2355,53 @@ var hmacSha256 = async (message, secret) => {
2319
2355
  const sigBuffer = await crypto.subtle.sign("HMAC", key, encoder.encode(message));
2320
2356
  return Array.from(new Uint8Array(sigBuffer)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
2321
2357
  };
2358
+ var parseOAuth2TokenResponse = (value, accessTokenPath) => {
2359
+ if (!isObject(value)) {
2360
+ throw new Error("OAuth token endpoint returned a non-object response");
2361
+ }
2362
+ const oauthError = Reflect.get(value, "error");
2363
+ if (typeof oauthError === "string" && oauthError.length > 0) {
2364
+ throw new Error(`OAuth token exchange failed: ${oauthError}`);
2365
+ }
2366
+ const response = { ...value };
2367
+ const nestedToken = accessTokenPath ? readPath(value, accessTokenPath) : undefined;
2368
+ if (typeof nestedToken === "string" && nestedToken.length > 0) {
2369
+ response.access_token = nestedToken;
2370
+ }
2371
+ if (typeof response.access_token !== "string" || response.access_token.length === 0) {
2372
+ throw new Error("OAuth token endpoint returned no access_token");
2373
+ }
2374
+ for (const key of ["refresh_token", "token_type", "scope", "id_token"]) {
2375
+ const field = response[key];
2376
+ if (field !== undefined && typeof field !== "string") {
2377
+ throw new Error(`OAuth token endpoint returned invalid ${key}: expected string`);
2378
+ }
2379
+ }
2380
+ const expiresIn = response.expires_in;
2381
+ if (typeof expiresIn === "string" && expiresIn.trim() !== "") {
2382
+ response.expires_in = Number(expiresIn);
2383
+ }
2384
+ if (response.expires_in !== undefined && (typeof response.expires_in !== "number" || !Number.isFinite(response.expires_in) || response.expires_in < 0)) {
2385
+ throw new Error("OAuth token endpoint returned invalid expires_in: expected a non-negative number");
2386
+ }
2387
+ return response;
2388
+ };
2389
+ var readIdentityKey = (value, key) => {
2390
+ if (Array.isArray(value)) {
2391
+ if (!/^\d+$/.test(key)) {
2392
+ throw new Error(`Invalid identity data shape: expected an array index, got ${key}`);
2393
+ }
2394
+ return value[Number(key)];
2395
+ }
2396
+ if (!isObject(value)) {
2397
+ throw new Error(`Invalid identity data shape: expected object, got ${typeof value}`);
2398
+ }
2399
+ return value[key];
2400
+ };
2322
2401
  var extractPropFromIdentity = (identity, keys, propType) => {
2323
2402
  let value = identity;
2324
2403
  for (const key of keys) {
2325
- if (Array.isArray(value))
2326
- value = value[Number(key)];
2327
- if (!isObject(value)) {
2328
- throw new Error(`Invalid identity data shape: expected object, got ${typeof value}`);
2329
- }
2330
- value = value[key];
2404
+ value = readIdentityKey(value, key);
2331
2405
  }
2332
2406
  if (propType !== undefined && !isExpectedType(value, propType)) {
2333
2407
  throw new Error(`Invalid identity data shape: expected ${propType}, got ${typeof value}`);
@@ -2362,6 +2436,13 @@ var normalizeProviderIdentity = ({
2362
2436
  const normalizedIdentity = structuredClone(identity);
2363
2437
  return setPropInIdentity(normalizedIdentity, canonicalKeys, subject);
2364
2438
  };
2439
+ var DAYS_IN_APPLE_CLIENT_SECRET_LIFETIME = 180;
2440
+ var HOURS_PER_DAY = 24;
2441
+ var MINUTES_PER_HOUR = 60;
2442
+ var SECONDS_PER_MINUTE = 60;
2443
+ var APPLE_CLIENT_SECRET_LIFETIME_SECONDS = SECONDS_PER_MINUTE * MINUTES_PER_HOUR * HOURS_PER_DAY * DAYS_IN_APPLE_CLIENT_SECRET_LIFETIME;
2444
+ var APPLE_ISSUER = "https://appleid.apple.com";
2445
+ var MILLISECONDS_PER_SECOND = 1000;
2365
2446
  var createS256CodeChallenge = async (codeVerifier) => {
2366
2447
  const data = new TextEncoder().encode(codeVerifier);
2367
2448
  const hashBuffer = await crypto.subtle.digest("SHA-256", data);
@@ -2374,20 +2455,40 @@ var createRandomBase64UrlGenerator = (length) => () => {
2374
2455
  var generateCodeVerifier = createRandomBase64UrlGenerator(NUM_GENERATOR_BYTES);
2375
2456
  var generateState = createRandomBase64UrlGenerator(NUM_GENERATOR_BYTES);
2376
2457
  var base64Url = (input) => encodeBase64(input).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
2458
+ var encodeJwtPart = (value) => base64Url(new TextEncoder().encode(JSON.stringify(value)));
2459
+ var createAppleClientSecret = async (credentials) => {
2460
+ const issuedAt = Math.floor(Date.now() / MILLISECONDS_PER_SECOND);
2461
+ const header = encodeJwtPart({
2462
+ alg: "ES256",
2463
+ kid: credentials.keyId,
2464
+ typ: "JWT"
2465
+ });
2466
+ const payload = encodeJwtPart({
2467
+ aud: APPLE_ISSUER,
2468
+ exp: issuedAt + APPLE_CLIENT_SECRET_LIFETIME_SECONDS,
2469
+ iat: issuedAt,
2470
+ iss: credentials.teamId,
2471
+ sub: credentials.clientId
2472
+ });
2473
+ const signingInput = `${header}.${payload}`;
2474
+ const privateKey = await crypto.subtle.importKey("pkcs8", Uint8Array.from(credentials.pkcs8PrivateKey), { name: "ECDSA", namedCurve: "P-256" }, false, ["sign"]);
2475
+ const signature = await crypto.subtle.sign({ hash: "SHA-256", name: "ECDSA" }, privateKey, new TextEncoder().encode(signingInput));
2476
+ return `${signingInput}.${base64Url(signature)}`;
2477
+ };
2377
2478
  var ALG_ES256 = "ES256";
2378
2479
  var ALG_RS256 = "RS256";
2379
2480
  var CLOCK_SKEW_SECONDS = 60;
2380
2481
  var DEFAULT_SCOPES = ["openid", "email", "profile"];
2381
2482
  var JWKS_REFETCH_COOLDOWN_MS = 60000;
2382
2483
  var JWT_SEGMENT_COUNT = 3;
2383
- var MILLISECONDS_PER_SECOND = 1000;
2484
+ var MILLISECONDS_PER_SECOND2 = 1000;
2384
2485
  var trimTrailingSlash = (value) => value.endsWith("/") ? value.slice(0, -1) : value;
2385
2486
  var fetchJson = async (url) => {
2386
2487
  const response = await fetch(url, {
2387
2488
  headers: { accept: "application/json" }
2388
2489
  });
2389
2490
  if (!response.ok) {
2390
- throw new Error(`Request to ${url} failed with status ${response.status}`);
2491
+ throw await createOAuth2FetchError(response);
2391
2492
  }
2392
2493
  return response.json();
2393
2494
  };
@@ -2418,11 +2519,14 @@ var verifySignature = (key, alg, signingInput, signature) => {
2418
2519
  var selectKey = (jwks, kid) => jwks.find((jwk) => kid === undefined || jwk.kid === kid);
2419
2520
  var assertClaims = (payload, expected) => {
2420
2521
  const aud = Reflect.get(payload, "aud");
2522
+ const azp = Reflect.get(payload, "azp");
2421
2523
  const exp = Reflect.get(payload, "exp");
2524
+ const iat = Reflect.get(payload, "iat");
2422
2525
  const iss = Reflect.get(payload, "iss");
2526
+ const nbf = Reflect.get(payload, "nbf");
2423
2527
  const sub = Reflect.get(payload, "sub");
2424
2528
  const audiences = Array.isArray(aud) ? aud : [aud];
2425
- const nowSeconds = Math.floor(Date.now() / MILLISECONDS_PER_SECOND);
2529
+ const nowSeconds = Math.floor(Date.now() / MILLISECONDS_PER_SECOND2);
2426
2530
  if (iss !== expected.issuer) {
2427
2531
  throw new Error('id_token "iss" does not match the provider issuer');
2428
2532
  }
@@ -2432,9 +2536,24 @@ var assertClaims = (payload, expected) => {
2432
2536
  if (!audiences.includes(expected.audience)) {
2433
2537
  throw new Error('id_token "aud" does not include the client id');
2434
2538
  }
2539
+ if (audiences.some((audience) => typeof audience !== "string") || typeof aud !== "string" && !Array.isArray(aud)) {
2540
+ throw new Error('id_token "aud" must be a string or string array');
2541
+ }
2542
+ if (audiences.length > 1 && (typeof azp !== "string" || azp !== expected.audience)) {
2543
+ throw new Error('id_token with multiple audiences requires matching "azp"');
2544
+ }
2435
2545
  if (typeof exp !== "number" || exp + CLOCK_SKEW_SECONDS < nowSeconds) {
2436
2546
  throw new Error("id_token has expired");
2437
2547
  }
2548
+ if (typeof iat !== "number") {
2549
+ throw new Error('id_token is missing numeric "iat"');
2550
+ }
2551
+ if (iat > nowSeconds + CLOCK_SKEW_SECONDS) {
2552
+ throw new Error('id_token "iat" is in the future');
2553
+ }
2554
+ if (nbf !== undefined && (typeof nbf !== "number" || nbf > nowSeconds + CLOCK_SKEW_SECONDS)) {
2555
+ throw new Error("id_token is not active yet");
2556
+ }
2438
2557
  if (expected.nonce !== undefined && Reflect.get(payload, "nonce") !== expected.nonce) {
2439
2558
  throw new Error('id_token "nonce" does not match');
2440
2559
  }
@@ -2561,9 +2680,9 @@ var createOIDCClient = async (config) => {
2561
2680
  method: "POST"
2562
2681
  });
2563
2682
  if (!response.ok) {
2564
- throw new Error(`OIDC token request failed with status ${response.status}`);
2683
+ throw await createOAuth2FetchError(response);
2565
2684
  }
2566
- const tokens = await response.json();
2685
+ const tokens = parseOAuth2TokenResponse(await response.json());
2567
2686
  return tokens;
2568
2687
  };
2569
2688
  const verifyToken = async (idToken, options) => {
@@ -2609,20 +2728,26 @@ var createOIDCClient = async (config) => {
2609
2728
  };
2610
2729
  var oidcProviderOptions = Object.keys(providers).filter(isOIDCProviderOption);
2611
2730
  var pkceProviderOptions = Object.keys(providers).filter(isPKCEProviderOption);
2731
+ var profileProviderOptions = Object.keys(providers).filter(isProfileProviderOption);
2612
2732
  var providerOptions = Object.keys(providers).filter(isValidProviderOption);
2613
2733
  var refreshableProviderOptions = Object.keys(providers).filter(isRefreshableProviderOption);
2614
2734
  var revocableProviderOptions = Object.keys(providers).filter(isRevocableProviderOption);
2615
2735
  var scopeRequiredProviderOptions = Object.keys(providers).filter(isScopeRequiredProviderOption);
2616
- var readPath = (value, path) => path.reduce((cursor, key) => cursor && typeof cursor === "object" ? Reflect.get(cursor, key) : undefined, value);
2617
2736
  var buildOAuth2Client = async (meta, config) => {
2618
2737
  const isConfigPropertyFunction = (cfgProp) => typeof cfgProp === "function";
2619
2738
  const resolveConfigProp = async (cfgProp) => {
2620
2739
  const result = isConfigPropertyFunction(cfgProp) ? cfgProp(config) : cfgProp;
2621
2740
  return result;
2622
2741
  };
2742
+ const resolveClientSecret = async () => {
2743
+ if (meta.createClientSecret) {
2744
+ return resolveConfigProp(meta.createClientSecret);
2745
+ }
2746
+ return hasClientSecret(config) ? config.clientSecret : undefined;
2747
+ };
2623
2748
  const authorizationUrl = await resolveConfigProp(meta.authorizationUrl);
2624
2749
  const tokenUrl = await resolveConfigProp(meta.tokenRequest.url);
2625
- return {
2750
+ const client = {
2626
2751
  async createAuthorizationUrl(opts) {
2627
2752
  const { state, scope = [], searchParams = [], codeVerifier } = opts;
2628
2753
  const url = new URL(authorizationUrl);
@@ -2643,7 +2768,7 @@ var buildOAuth2Client = async (meta, config) => {
2643
2768
  url.searchParams.set("code_challenge_method", meta.PKCEMethod);
2644
2769
  url.searchParams.set("code_challenge", codeChallenge);
2645
2770
  }
2646
- Object.entries(resolveConfigProp(meta.createAuthorizationURLSearchParams) ?? {}).forEach(([key, value]) => url.searchParams.set(key, value));
2771
+ Object.entries(await resolveConfigProp(meta.createAuthorizationURLSearchParams) ?? {}).forEach(([key, value]) => url.searchParams.set(key, value));
2647
2772
  searchParams.forEach(([key, value]) => url.searchParams.set(key, value));
2648
2773
  return url;
2649
2774
  },
@@ -2676,7 +2801,7 @@ var buildOAuth2Client = async (meta, config) => {
2676
2801
  if (authIn === "header") {
2677
2802
  profileHeaders.Authorization = `Bearer ${accessToken}`;
2678
2803
  } else if (authIn === "path") {
2679
- endpoint.pathname = `${endpoint.pathname.replace(/\/+$/, "")}/${accessToken}`;
2804
+ endpoint.pathname = `${endpoint.pathname.replace(/\/+$/, "")}/${encodeURIComponent(accessToken)}`;
2680
2805
  } else {
2681
2806
  endpoint.searchParams.append("access_token", accessToken);
2682
2807
  }
@@ -2697,9 +2822,8 @@ var buildOAuth2Client = async (meta, config) => {
2697
2822
  params.set("grant_type", "refresh_token");
2698
2823
  params.set("refresh_token", refreshToken);
2699
2824
  const { clientId } = config;
2700
- let clientSecretValue;
2701
- if (hasClientSecret(config)) {
2702
- clientSecretValue = config.clientSecret;
2825
+ const clientSecretValue = await resolveClientSecret();
2826
+ if (clientSecretValue) {
2703
2827
  params.set("client_id", clientId);
2704
2828
  params.set("client_secret", clientSecretValue);
2705
2829
  }
@@ -2714,60 +2838,99 @@ var buildOAuth2Client = async (meta, config) => {
2714
2838
  const response = await fetch(request);
2715
2839
  if (!response.ok)
2716
2840
  throw await createOAuth2FetchError(response);
2717
- return response.json();
2841
+ return parseOAuth2TokenResponse(await response.json());
2842
+ },
2843
+ resolveRevocationInput(context) {
2844
+ const { revocationRequest } = meta;
2845
+ if (!revocationRequest) {
2846
+ throw new Error("Token revocation not defined for this provider");
2847
+ }
2848
+ const inputSource = revocationRequest.inputSource ?? "accessToken";
2849
+ const input = context[inputSource];
2850
+ if (input === undefined) {
2851
+ throw new Error(`Revocation requires ${inputSource}, but it was not provided`);
2852
+ }
2853
+ const expectsNumber = revocationRequest.authIn !== "header" && revocationRequest.inputType === "number";
2854
+ if (expectsNumber && (typeof input !== "number" || !Number.isFinite(input))) {
2855
+ throw new TypeError("This provider requires a numeric revocation input");
2856
+ }
2857
+ if (!expectsNumber && typeof input !== "string") {
2858
+ throw new TypeError("This provider requires a string revocation input");
2859
+ }
2860
+ return input;
2718
2861
  },
2719
- async revokeToken(token) {
2862
+ async revokeToken(input) {
2720
2863
  const { revocationRequest } = meta;
2721
2864
  if (!revocationRequest) {
2722
2865
  throw new Error("Token revocation not defined for this provider");
2723
2866
  }
2724
- const { url, authIn, body, headers, tokenParamName } = revocationRequest;
2867
+ if (revocationRequest.authIn !== "header" && revocationRequest.inputType === "number" && (typeof input !== "number" || !Number.isFinite(input))) {
2868
+ throw new TypeError("This provider requires a numeric revocation input");
2869
+ }
2870
+ const {
2871
+ url,
2872
+ authIn,
2873
+ body,
2874
+ encoding,
2875
+ headers,
2876
+ includeClientCredentials = true,
2877
+ tokenParamName,
2878
+ validateResponse
2879
+ } = revocationRequest;
2725
2880
  const endpoint = await resolveConfigProp(url);
2726
2881
  const resolvedBody = await resolveConfigProp(body);
2727
- const revocationBody = new URLSearchParams(resolvedBody);
2882
+ const revocationBody = resolvedBody === undefined ? undefined : new URLSearchParams(resolvedBody);
2728
2883
  const revocationHeaders = new Headers(headers && await resolveConfigProp(headers));
2729
2884
  const { clientId } = config;
2730
- const clientSecret = hasClientSecret(config) ? config.clientSecret : undefined;
2885
+ const clientSecret = await resolveClientSecret();
2731
2886
  let request;
2732
2887
  if (authIn === "body") {
2733
- revocationBody.set(tokenParamName, token);
2734
- revocationBody.set("client_id", clientId);
2735
- if (clientSecret)
2736
- revocationBody.set("client_secret", clientSecret);
2888
+ const bodyWithToken = revocationBody ?? new URLSearchParams;
2889
+ bodyWithToken.set(tokenParamName, String(input));
2890
+ const hasAuthorizationHeader = revocationHeaders.has("Authorization");
2891
+ if (includeClientCredentials && !hasAuthorizationHeader)
2892
+ bodyWithToken.set("client_id", clientId);
2893
+ if (includeClientCredentials && !hasAuthorizationHeader && clientSecret)
2894
+ bodyWithToken.set("client_secret", clientSecret);
2737
2895
  request = createOAuth2Request({
2738
- authIn: "body",
2739
- body: revocationBody,
2896
+ authIn: hasAuthorizationHeader || !includeClientCredentials ? "query" : "body",
2897
+ body: bodyWithToken,
2740
2898
  clientId,
2741
2899
  clientSecret,
2742
- encoding: "application/x-www-form-urlencoded",
2900
+ encoding,
2743
2901
  headers: revocationHeaders,
2744
2902
  url: endpoint.toString()
2745
2903
  });
2746
2904
  } else if (authIn === "header") {
2747
- revocationHeaders.set("Authorization", `Bearer ${token}`);
2905
+ revocationHeaders.set("Authorization", `Bearer ${String(input)}`);
2748
2906
  request = createOAuth2Request({
2749
- authIn: "header",
2907
+ authIn: "query",
2750
2908
  body: revocationBody,
2751
2909
  clientId,
2752
- clientSecret,
2753
- encoding: "application/x-www-form-urlencoded",
2910
+ encoding,
2754
2911
  headers: revocationHeaders,
2755
2912
  url: endpoint.toString()
2756
2913
  });
2757
2914
  } else {
2915
+ const queryEndpoint = new URL(endpoint);
2916
+ queryEndpoint.searchParams.set(tokenParamName, String(input));
2758
2917
  request = createOAuth2Request({
2759
2918
  authIn: "query",
2760
2919
  body: revocationBody,
2761
2920
  clientId,
2762
- clientSecret,
2763
- encoding: "application/x-www-form-urlencoded",
2921
+ encoding,
2764
2922
  headers: revocationHeaders,
2765
- url: `${endpoint.toString()}?${tokenParamName}=${token}`
2923
+ url: queryEndpoint.toString()
2766
2924
  });
2767
2925
  }
2768
2926
  const response = await fetch(request);
2769
2927
  if (!response.ok)
2770
2928
  throw await createOAuth2FetchError(response);
2929
+ if (validateResponse) {
2930
+ await validateResponse(await response.json().catch(() => {
2931
+ return;
2932
+ }));
2933
+ }
2771
2934
  },
2772
2935
  async validateAuthorizationCode(opts) {
2773
2936
  const { code, codeVerifier } = opts;
@@ -2793,32 +2956,27 @@ var buildOAuth2Client = async (meta, config) => {
2793
2956
  authIn,
2794
2957
  body: payload,
2795
2958
  clientId: config.clientId,
2796
- clientSecret: hasClientSecret(config) ? config.clientSecret : undefined,
2959
+ clientSecret: await resolveClientSecret(),
2797
2960
  encoding,
2798
2961
  url: tokenUrl
2799
2962
  });
2800
2963
  const response = await fetch(request);
2801
2964
  if (!response.ok)
2802
2965
  throw await createOAuth2FetchError(response);
2803
- const tokenResponse = await response.json();
2804
- if (!tokenResponse || typeof tokenResponse !== "object") {
2805
- throw new Error("OAuth token endpoint returned a non-object response");
2806
- }
2807
- const oauthError = Reflect.get(tokenResponse, "error");
2808
- if (typeof oauthError === "string" && oauthError.length > 0) {
2809
- throw new Error(`OAuth token exchange failed: ${oauthError}`);
2810
- }
2811
- const nestedToken = meta.accessTokenPath ? readPath(tokenResponse, meta.accessTokenPath) : undefined;
2812
- if (typeof nestedToken === "string" && nestedToken.length > 0 && tokenResponse && typeof tokenResponse === "object") {
2813
- tokenResponse.access_token = nestedToken;
2814
- }
2815
- const accessToken = Reflect.get(tokenResponse, "access_token");
2816
- if (typeof accessToken !== "string" || accessToken.length === 0) {
2817
- throw new Error("OAuth token endpoint returned no access_token");
2818
- }
2819
- return tokenResponse;
2966
+ return parseOAuth2TokenResponse(await response.json(), meta.accessTokenPath);
2820
2967
  }
2821
2968
  };
2969
+ if (!meta.profileRequest) {
2970
+ Reflect.deleteProperty(client, "fetchUserProfile");
2971
+ }
2972
+ if (!meta.isRefreshable) {
2973
+ Reflect.deleteProperty(client, "refreshAccessToken");
2974
+ }
2975
+ if (!meta.revocationRequest) {
2976
+ Reflect.deleteProperty(client, "resolveRevocationInput");
2977
+ Reflect.deleteProperty(client, "revokeToken");
2978
+ }
2979
+ return client;
2822
2980
  };
2823
2981
  var createCustomOAuth2Client = (providerConfig, credentials) => buildOAuth2Client(providerConfig, credentials);
2824
2982
  var createOAuth2Client = (providerName, config) => buildOAuth2Client(providers[providerName], config);
@@ -4576,7 +4734,15 @@ var instantiateUserSession = async ({
4576
4734
  providerInstance,
4577
4735
  tokenResponse
4578
4736
  });
4579
- const { accessToken, refreshToken, userIdentity } = authorization;
4737
+ const {
4738
+ accessToken,
4739
+ oauthSubject: resolvedOAuthSubject,
4740
+ refreshToken,
4741
+ userIdentity
4742
+ } = authorization;
4743
+ const providerMeta = providerConfiguration ?? (isValidProviderOption(authProvider) ? providers[authProvider] : undefined);
4744
+ const extractedSubject = providerMeta ? extractPropFromIdentity(userIdentity, providerMeta.subject, providerMeta.subjectType) : Reflect.get(userIdentity, "sub");
4745
+ const oauthSubject = resolvedOAuthSubject ?? (typeof extractedSubject === "string" || typeof extractedSubject === "number" ? extractedSubject : undefined);
4580
4746
  const userSession = validateSession({ session, user_session_id });
4581
4747
  const userSessionId = getUserSessionId({
4582
4748
  cookieSecure,
@@ -4593,6 +4759,7 @@ var instantiateUserSession = async ({
4593
4759
  accessToken,
4594
4760
  authenticatedAt: Date.now(),
4595
4761
  expiresAt: Date.now() + sessionDurationMs,
4762
+ oauthSubject,
4596
4763
  refreshToken,
4597
4764
  user
4598
4765
  };
@@ -4602,6 +4769,7 @@ var instantiateUserSession = async ({
4602
4769
  if (existingUnregistered) {
4603
4770
  existingUnregistered.accessToken = accessToken;
4604
4771
  existingUnregistered.expiresAt = Date.now() + unregisteredSessionDurationMs;
4772
+ existingUnregistered.oauthSubject = oauthSubject;
4605
4773
  existingUnregistered.refreshToken = refreshToken;
4606
4774
  existingUnregistered.userIdentity = userIdentity;
4607
4775
  return response;
@@ -4609,6 +4777,7 @@ var instantiateUserSession = async ({
4609
4777
  unregisteredSession[userSessionId] = {
4610
4778
  accessToken,
4611
4779
  expiresAt: Date.now() + unregisteredSessionDurationMs,
4780
+ oauthSubject,
4612
4781
  refreshToken,
4613
4782
  userIdentity
4614
4783
  };
@@ -4657,6 +4826,9 @@ var resolveOAuthAuthorization = async ({
4657
4826
  accessToken = readOptionalString(withingsBody, "access_token") ?? accessToken;
4658
4827
  refreshToken = readOptionalString(withingsBody, "refresh_token") ?? refreshToken;
4659
4828
  } else {
4829
+ if (!isProfileOAuth2Client(providerInstance)) {
4830
+ throw new Error(`Provider "${authProvider}" returned no identity and has no profile endpoint`);
4831
+ }
4660
4832
  userIdentity = normalizeProviderIdentity({
4661
4833
  identity: await providerInstance.fetchUserProfile(accessToken),
4662
4834
  providerConfiguration: meta,
@@ -4664,9 +4836,14 @@ var resolveOAuthAuthorization = async ({
4664
4836
  });
4665
4837
  }
4666
4838
  const tokenType = Reflect.get(tokenResponse, "token_type");
4839
+ const oauthSubject = extractPropFromIdentity(userIdentity, meta.subject, meta.subjectType);
4840
+ if (typeof oauthSubject !== "string" && typeof oauthSubject !== "number") {
4841
+ throw new Error(`Provider "${authProvider}" returned an invalid OAuth subject`);
4842
+ }
4667
4843
  return {
4668
4844
  accessToken,
4669
4845
  expiresAt: resolveOAuthTokenExpiresAt(tokenResponse, now),
4846
+ oauthSubject,
4670
4847
  refreshToken,
4671
4848
  tokenType: typeof tokenType === "string" ? tokenType : undefined,
4672
4849
  userIdentity
@@ -6614,10 +6791,10 @@ var exchangeBackchannelAuth = async ({
6614
6791
  init_constants();
6615
6792
  var CLIENT_ASSERTION_TYPE = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
6616
6793
  var MAX_ASSERTION_LIFETIME_MINUTES = 5;
6617
- var SECONDS_PER_MINUTE = 60;
6618
- var MAX_ASSERTION_LIFETIME_MS = MAX_ASSERTION_LIFETIME_MINUTES * SECONDS_PER_MINUTE * MILLISECONDS_IN_A_SECOND;
6794
+ var SECONDS_PER_MINUTE2 = 60;
6795
+ var MAX_ASSERTION_LIFETIME_MS = MAX_ASSERTION_LIFETIME_MINUTES * SECONDS_PER_MINUTE2 * MILLISECONDS_IN_A_SECOND;
6619
6796
  var jwksCache = new Map;
6620
- var JWKS_CACHE_TTL_MS = SECONDS_PER_MINUTE * MILLISECONDS_IN_A_SECOND;
6797
+ var JWKS_CACHE_TTL_MS = SECONDS_PER_MINUTE2 * MILLISECONDS_IN_A_SECOND;
6621
6798
  var JWKS_FETCH_TIMEOUT_SECONDS = 5;
6622
6799
  var JWKS_FETCH_TIMEOUT_MS = JWKS_FETCH_TIMEOUT_SECONDS * MILLISECONDS_IN_A_SECOND;
6623
6800
  var fetchJwksUri = async (jwksUri) => {
@@ -10174,6 +10351,7 @@ var callback = ({
10174
10351
  // src/routes/profile.ts
10175
10352
  import { Elysia as Elysia29, t as t22 } from "elysia";
10176
10353
  var profile = ({
10354
+ authSessionStore,
10177
10355
  clientProviders,
10178
10356
  profileRoute = "/oauth2/profile",
10179
10357
  onProfileSuccess,
@@ -10188,9 +10366,6 @@ var profile = ({
10188
10366
  if (auth_provider.value === undefined) {
10189
10367
  return status("Unauthorized", "No auth provider found");
10190
10368
  }
10191
- if (!isValidProviderOption(auth_provider.value)) {
10192
- return status("Unauthorized", "Invalid provider");
10193
- }
10194
10369
  if (user_session_id.value === undefined) {
10195
10370
  return status("Unauthorized", "No user session found");
10196
10371
  }
@@ -10203,7 +10378,14 @@ var profile = ({
10203
10378
  return status("Unauthorized", resolvedProvider.error);
10204
10379
  }
10205
10380
  const { clientName, providerInstance } = resolvedProvider.entry;
10206
- const userSession = session[user_session_id.value];
10381
+ if (!isProfileOAuth2Client(providerInstance)) {
10382
+ return status("Not Implemented", "Provider does not expose a profile endpoint");
10383
+ }
10384
+ const userSession = await loadSessionFromSource({
10385
+ authSessionStore,
10386
+ session,
10387
+ userSessionId: user_session_id.value
10388
+ });
10207
10389
  if (userSession === undefined) {
10208
10390
  return status("Unauthorized", "No user session found");
10209
10391
  }
@@ -10255,9 +10437,6 @@ var refresh = ({
10255
10437
  if (auth_provider.value === undefined) {
10256
10438
  return status("Unauthorized", "No auth provider found");
10257
10439
  }
10258
- if (!isValidProviderOption(auth_provider.value)) {
10259
- return status("Bad Request", "Invalid provider");
10260
- }
10261
10440
  if (user_session_id.value === undefined) {
10262
10441
  return status("Unauthorized", "No user session found");
10263
10442
  }
@@ -10279,7 +10458,7 @@ var refresh = ({
10279
10458
  return status("Unauthorized", "No user session found");
10280
10459
  }
10281
10460
  const { refreshToken } = userSession;
10282
- if (!isRefreshableOAuth2Client(auth_provider.value, providerInstance)) {
10461
+ if (!isRefreshableOAuth2Client(providerInstance)) {
10283
10462
  return status("Not Implemented", "Provider is not refreshable");
10284
10463
  }
10285
10464
  if (refreshToken === undefined) {
@@ -10339,9 +10518,6 @@ var revoke = ({
10339
10518
  if (auth_provider.value === undefined) {
10340
10519
  return status("Unauthorized", "No auth provider found");
10341
10520
  }
10342
- if (!isValidProviderOption(auth_provider.value)) {
10343
- return status("Bad Request", "Invalid provider");
10344
- }
10345
10521
  if (user_session_id.value === undefined) {
10346
10522
  return status("Unauthorized", "No user session found");
10347
10523
  }
@@ -10354,7 +10530,7 @@ var revoke = ({
10354
10530
  return status("Unauthorized", resolvedProvider.error);
10355
10531
  }
10356
10532
  const { clientName, providerInstance } = resolvedProvider.entry;
10357
- if (!isRevocableOAuth2Client(auth_provider.value, providerInstance)) {
10533
+ if (!isRevocableOAuth2Client(providerInstance)) {
10358
10534
  return status("Not Implemented", "Provider does not support revocation");
10359
10535
  }
10360
10536
  const userSession = await loadSessionFromSource({
@@ -10365,16 +10541,21 @@ var revoke = ({
10365
10541
  if (userSession === undefined) {
10366
10542
  return status("Unauthorized", "No user session found");
10367
10543
  }
10368
- const { accessToken } = userSession;
10544
+ const { accessToken, oauthSubject, refreshToken } = userSession;
10369
10545
  if (accessToken === undefined) {
10370
10546
  return status("Bad Request", "Session has no access token to revoke");
10371
10547
  }
10372
10548
  try {
10373
- await providerInstance.revokeToken(accessToken);
10549
+ const tokenToRevoke = providerInstance.resolveRevocationInput({
10550
+ accessToken,
10551
+ refreshToken,
10552
+ subject: oauthSubject
10553
+ });
10554
+ await providerInstance.revokeToken(tokenToRevoke);
10374
10555
  await onRevocationSuccess?.({
10375
10556
  authClient: clientName,
10376
10557
  authProvider: auth_provider.value,
10377
- tokenToRevoke: accessToken
10558
+ tokenToRevoke
10378
10559
  });
10379
10560
  return new Response("Token revoked", {
10380
10561
  status: 204
@@ -24214,6 +24395,7 @@ var authSessionsTable = pgTable("auth_sessions", {
24214
24395
  created_at: timestamp("created_at").notNull().defaultNow(),
24215
24396
  expires_at_ms: bigint("expires_at_ms", { mode: "number" }).notNull(),
24216
24397
  id: varchar("id", { length: 255 }).primaryKey(),
24398
+ oauth_subject_json: jsonb("oauth_subject_json").$type(),
24217
24399
  refresh_token: text("refresh_token"),
24218
24400
  updated_at: timestamp("updated_at").notNull().defaultNow(),
24219
24401
  user_json: jsonb("user_json").$type().notNull()
@@ -24223,6 +24405,7 @@ var authUnregisteredSessionsTable = pgTable("auth_unregistered_sessions", {
24223
24405
  created_at: timestamp("created_at").notNull().defaultNow(),
24224
24406
  expires_at_ms: bigint("expires_at_ms", { mode: "number" }).notNull(),
24225
24407
  id: varchar("id", { length: 255 }).primaryKey(),
24408
+ oauth_subject_json: jsonb("oauth_subject_json").$type(),
24226
24409
  refresh_token: text("refresh_token"),
24227
24410
  session_information_json: jsonb("session_information_json").$type(),
24228
24411
  updated_at: timestamp("updated_at").notNull().defaultNow(),
@@ -24240,12 +24423,14 @@ var toSessionData = (row, decodeUser) => ({
24240
24423
  accessToken: row.access_token ?? undefined,
24241
24424
  authenticatedAt: row.authenticated_at_ms ?? undefined,
24242
24425
  expiresAt: row.expires_at_ms,
24426
+ oauthSubject: row.oauth_subject_json ?? undefined,
24243
24427
  refreshToken: row.refresh_token ?? undefined,
24244
24428
  user: cloneUser(decodeUser(row.user_json))
24245
24429
  });
24246
24430
  var toUnregisteredSessionData = (row) => ({
24247
24431
  accessToken: row.access_token ?? undefined,
24248
24432
  expiresAt: row.expires_at_ms,
24433
+ oauthSubject: row.oauth_subject_json ?? undefined,
24249
24434
  refreshToken: row.refresh_token ?? undefined,
24250
24435
  sessionInformation: cloneRecord(row.session_information_json ?? undefined),
24251
24436
  userIdentity: cloneRecord(row.user_identity_json ?? undefined)
@@ -24290,6 +24475,7 @@ var createNeonAuthSessionStore = (databaseUrl, decodeUser) => {
24290
24475
  authenticated_at_ms: value.authenticatedAt ?? null,
24291
24476
  expires_at_ms: value.expiresAt,
24292
24477
  id,
24478
+ oauth_subject_json: value.oauthSubject ?? null,
24293
24479
  refresh_token: value.refreshToken ?? null,
24294
24480
  updated_at: new Date,
24295
24481
  user_json: value.user ?? {}
@@ -24298,6 +24484,7 @@ var createNeonAuthSessionStore = (databaseUrl, decodeUser) => {
24298
24484
  access_token: value.accessToken ?? null,
24299
24485
  authenticated_at_ms: value.authenticatedAt ?? null,
24300
24486
  expires_at_ms: value.expiresAt,
24487
+ oauth_subject_json: value.oauthSubject ?? null,
24301
24488
  refresh_token: value.refreshToken ?? null,
24302
24489
  updated_at: new Date,
24303
24490
  user_json: value.user ?? {}
@@ -24310,6 +24497,7 @@ var createNeonAuthSessionStore = (databaseUrl, decodeUser) => {
24310
24497
  access_token: value.accessToken ?? null,
24311
24498
  expires_at_ms: value.expiresAt,
24312
24499
  id,
24500
+ oauth_subject_json: value.oauthSubject ?? null,
24313
24501
  refresh_token: value.refreshToken ?? null,
24314
24502
  session_information_json: value.sessionInformation ?? null,
24315
24503
  updated_at: new Date,
@@ -24318,6 +24506,7 @@ var createNeonAuthSessionStore = (databaseUrl, decodeUser) => {
24318
24506
  set: {
24319
24507
  access_token: value.accessToken ?? null,
24320
24508
  expires_at_ms: value.expiresAt,
24509
+ oauth_subject_json: value.oauthSubject ?? null,
24321
24510
  refresh_token: value.refreshToken ?? null,
24322
24511
  session_information_json: value.sessionInformation ?? null,
24323
24512
  updated_at: new Date,
@@ -30357,6 +30546,7 @@ var sessionSchema = Type.Object({
30357
30546
  authenticatedAt: Type.Optional(Type.Number()),
30358
30547
  expiresAt: Type.Number(),
30359
30548
  impersonator: Type.Optional(impersonatorSchema),
30549
+ oauthSubject: Type.Optional(Type.Union([Type.String(), Type.Number()])),
30360
30550
  refreshToken: Type.Optional(Type.String()),
30361
30551
  samlLogout: Type.Optional(Type.Object({
30362
30552
  connectionId: Type.String(),
@@ -30368,6 +30558,7 @@ var sessionSchema = Type.Object({
30368
30558
  var unregisteredSessionSchema = Type.Object({
30369
30559
  accessToken: Type.Optional(Type.String()),
30370
30560
  expiresAt: Type.Number(),
30561
+ oauthSubject: Type.Optional(Type.Union([Type.String(), Type.Number()])),
30371
30562
  refreshToken: Type.Optional(Type.String()),
30372
30563
  sessionInformation: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
30373
30564
  userIdentity: Type.Optional(Type.Record(Type.String(), Type.Unknown()))
@@ -35952,30 +36143,40 @@ var JOURNAL_DDL = `CREATE TABLE IF NOT EXISTS "auth_migrations" (
35952
36143
  var isJournalRow = (value) => typeof value === "object" && value !== null && typeof Reflect.get(value, "id") === "string";
35953
36144
  var isBlockName = (value) => Object.hasOwn(blockMigrations, value);
35954
36145
  var allBlockNames = () => Object.keys(blockMigrations).filter(isBlockName);
35955
- var applyOne = async (pool, id, sql2, log) => {
35956
- await pool.query(sql2);
35957
- await pool.query(`INSERT INTO "auth_migrations" ("id", "applied_at_ms") VALUES ($1, $2)`, [id, Date.now()]);
36146
+ var applyOne = async (client, id, sql2, log) => {
36147
+ await client.query(sql2);
36148
+ await client.query(`INSERT INTO "auth_migrations" ("id", "applied_at_ms") VALUES ($1, $2)`, [id, Date.now()]);
35958
36149
  log(`apply ${id}`);
35959
36150
  };
35960
- var runOne = async (pool, id, sql2, applied, result, log) => {
36151
+ var runOne = async (client, id, sql2, applied, result, log) => {
35961
36152
  if (applied.has(id)) {
35962
36153
  result.skipped.push(id);
35963
36154
  log(`skip ${id}`);
35964
36155
  return;
35965
36156
  }
35966
- await applyOne(pool, id, sql2, log);
36157
+ await applyOne(client, id, sql2, log);
35967
36158
  result.applied.push(id);
35968
36159
  };
35969
36160
  var runMigrations = async ({
35970
36161
  blocks,
36162
+ client,
35971
36163
  databaseUrl,
35972
36164
  log = console.log
35973
36165
  }) => {
35974
- const pool = new Ln({ connectionString: databaseUrl });
36166
+ let ownedPool;
36167
+ let migrationClient;
36168
+ if (client !== undefined) {
36169
+ migrationClient = client;
36170
+ } else {
36171
+ if (databaseUrl === undefined)
36172
+ throw new Error("runMigrations requires databaseUrl or client");
36173
+ ownedPool = new Ln({ connectionString: databaseUrl });
36174
+ migrationClient = ownedPool;
36175
+ }
35975
36176
  const result = { applied: [], skipped: [] };
35976
36177
  try {
35977
- await pool.query(JOURNAL_DDL);
35978
- const journal = await pool.query(`SELECT "id" FROM "auth_migrations"`);
36178
+ await migrationClient.query(JOURNAL_DDL);
36179
+ const journal = await migrationClient.query(`SELECT "id" FROM "auth_migrations"`);
35979
36180
  const applied = new Set(journal.rows.filter(isJournalRow).map((row) => row.id));
35980
36181
  const selected = blocks ?? allBlockNames();
35981
36182
  const flat = selected.flatMap((block) => blockMigrations[block].migrations.map((migration) => ({
@@ -35984,10 +36185,10 @@ var runMigrations = async ({
35984
36185
  })));
35985
36186
  await flat.reduce(async (prior, item) => {
35986
36187
  await prior;
35987
- return runOne(pool, item.id, item.sql, applied, result, log);
36188
+ return runOne(migrationClient, item.id, item.sql, applied, result, log);
35988
36189
  }, Promise.resolve());
35989
36190
  } finally {
35990
- await pool.end();
36191
+ await ownedPool?.end();
35991
36192
  }
35992
36193
  return result;
35993
36194
  };
@@ -36020,6 +36221,14 @@ var oidcResourceAudienceMigration = {
36020
36221
  ].join(`
36021
36222
  `)
36022
36223
  };
36224
+ var sessionOAuthSubjectMigration = {
36225
+ id: "0002_oauth_subject",
36226
+ sql: [
36227
+ 'ALTER TABLE "auth_sessions" ADD COLUMN IF NOT EXISTS "oauth_subject_json" jsonb;',
36228
+ 'ALTER TABLE "auth_unregistered_sessions" ADD COLUMN IF NOT EXISTS "oauth_subject_json" jsonb;'
36229
+ ].join(`
36230
+ `)
36231
+ };
36023
36232
  var blockMigrations = {
36024
36233
  adaptive: initMigration("adaptive", [knownDevicesTable, loginHistoryTable]),
36025
36234
  agents: {
@@ -36088,10 +36297,16 @@ var blockMigrations = {
36088
36297
  portal: initMigration("portal", [setupSessionsTable]),
36089
36298
  roles: initMigration("roles", [rolesTable]),
36090
36299
  scim: initMigration("scim", [scimTokensTable]),
36091
- sessions: initMigration("sessions", [
36092
- authSessionsTable,
36093
- authUnregisteredSessionsTable
36094
- ]),
36300
+ sessions: {
36301
+ block: "sessions",
36302
+ migrations: [
36303
+ ...initMigration("sessions", [
36304
+ authSessionsTable,
36305
+ authUnregisteredSessionsTable
36306
+ ]).migrations,
36307
+ sessionOAuthSubjectMigration
36308
+ ]
36309
+ },
36095
36310
  sso: initMigration("sso", [ssoConnectionsTable, samlServiceProvidersTable]),
36096
36311
  vault: initMigration("vault", [vaultEntriesTable]),
36097
36312
  vc: initMigration("vc", [
@@ -36777,6 +36992,7 @@ var buildAuthApplications = async (configuration) => {
36777
36992
  resolveAuthIntent
36778
36993
  }),
36779
36994
  profile({
36995
+ authSessionStore,
36780
36996
  clientProviders,
36781
36997
  onProfileError,
36782
36998
  onProfileSuccess,
@@ -37366,5 +37582,5 @@ export {
37366
37582
  AGENT_CLAIM_GRANT_TYPE
37367
37583
  };
37368
37584
 
37369
- //# debugId=B232DF05F02E03AA64756E2164756E21
37585
+ //# debugId=72A82A16089AB9F664756E2164756E21
37370
37586
  //# sourceMappingURL=index.js.map