@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/server.js CHANGED
@@ -1363,17 +1363,23 @@ var providers = defineProviders({
1363
1363
  },
1364
1364
  apple: {
1365
1365
  authorizationUrl: "https://appleid.apple.com/auth/authorize",
1366
+ createAuthorizationURLSearchParams: {
1367
+ response_mode: "form_post"
1368
+ },
1369
+ createClientSecret: (config) => createAppleClientSecret(config),
1366
1370
  isOIDC: true,
1367
1371
  isRefreshable: true,
1368
- PKCEMethod: "S256",
1369
- profileRequest: {
1370
- authIn: "header",
1371
- encoding: "application/json",
1372
- method: "GET",
1373
- url: "https://appleid.apple.com/auth/userinfo"
1372
+ revocationRequest: {
1373
+ authIn: "body",
1374
+ encoding: "application/x-www-form-urlencoded",
1375
+ tokenParamName: "token",
1376
+ url: "https://appleid.apple.com/auth/revoke"
1374
1377
  },
1375
1378
  scopeRequired: false,
1376
- subject: ["id"],
1379
+ subject: ["sub"],
1380
+ subjectBySource: {
1381
+ idToken: ["sub"]
1382
+ },
1377
1383
  subjectType: "string",
1378
1384
  tokenRequest: {
1379
1385
  authIn: "body",
@@ -1442,6 +1448,7 @@ var providers = defineProviders({
1442
1448
  token_type_hint: "refresh_token"
1443
1449
  }),
1444
1450
  encoding: "application/json",
1451
+ inputSource: "refreshToken",
1445
1452
  tokenParamName: "token",
1446
1453
  url: (config) => `https://${config.domain}/oauth/revoke`
1447
1454
  },
@@ -2573,6 +2580,7 @@ var providers = defineProviders({
2573
2580
  token_type_hint: "refresh_token"
2574
2581
  }),
2575
2582
  encoding: "application/json",
2583
+ inputSource: "refreshToken",
2576
2584
  url: "https://www.reddit.com/api/v1/revoke_token"
2577
2585
  },
2578
2586
  scopeRequired: true,
@@ -2946,49 +2954,27 @@ var providers = defineProviders({
2946
2954
  authorizationUrl: "https://account.withings.com/oauth2_user/authorize2",
2947
2955
  isOIDC: false,
2948
2956
  isRefreshable: true,
2949
- profileRequest: {
2950
- authIn: "header",
2951
- body: async (config) => {
2952
- const props = await getWithingsProps(config);
2953
- if (props === undefined)
2954
- throw new Error("Failed to get Withings search properties");
2955
- const { nonce, hashedSignature } = props;
2956
- return [
2957
- ["action", "getuser"],
2958
- ["nonce", nonce],
2959
- ["client_id", config.clientId],
2960
- ["signature", hashedSignature]
2961
- ];
2962
- },
2963
- encoding: "application/x-www-form-urlencoded",
2964
- method: "POST",
2965
- url: "https://wbsapi.withings.net/v2/oauth2"
2966
- },
2967
2957
  refreshAccessTokenBody: {
2968
2958
  action: "requesttoken"
2969
2959
  },
2970
2960
  revocationRequest: {
2971
- authIn: "header",
2972
- body: async (config) => {
2973
- const props = await getWithingsProps(config);
2974
- if (!props)
2975
- throw new Error("Failed to get Withings props");
2976
- const { nonce, hashedSignature } = props;
2977
- return [
2978
- ["action", "revoke"],
2979
- ["client_id", config.clientId],
2980
- ["nonce", nonce],
2981
- ["signature", hashedSignature]
2982
- ];
2983
- },
2961
+ authIn: "body",
2962
+ body: (config) => getWithingsSignatureParams(config, "revoke"),
2984
2963
  encoding: "application/x-www-form-urlencoded",
2985
- method: "POST",
2986
- url: "https://wbsapi.withings.net/v2/oauth2"
2964
+ includeClientCredentials: false,
2965
+ inputSource: "subject",
2966
+ inputType: "number",
2967
+ tokenParamName: "userid",
2968
+ url: "https://wbsapi.withings.net/v2/oauth2",
2969
+ validateResponse: (value) => assertWithingsSuccess(value)
2987
2970
  },
2988
2971
  scopeDelimiter: ",",
2989
2972
  scopeRequired: true,
2990
2973
  subject: ["userid"],
2991
- subjectType: "string",
2974
+ subjectBySource: {
2975
+ tokenResponse: ["body", "userid"]
2976
+ },
2977
+ subjectType: "number",
2992
2978
  tokenRequest: {
2993
2979
  authIn: "body",
2994
2980
  encoding: "application/x-www-form-urlencoded",
@@ -3180,14 +3166,39 @@ var isPKCEProviderOption = (option) => {
3180
3166
  const provider = providers[option];
3181
3167
  return provider.PKCEMethod !== undefined;
3182
3168
  };
3183
- var isRefreshableOAuth2Client = (providerName, _client) => isRefreshableProviderOption(providerName);
3169
+ function isProfileOAuth2Client(providerOrClient, maybeClient) {
3170
+ const client = maybeClient ?? providerOrClient;
3171
+ if (maybeClient !== undefined && (typeof providerOrClient !== "string" || !isProfileProviderOption(providerOrClient))) {
3172
+ return false;
3173
+ }
3174
+ return typeof client === "object" && client !== null && "fetchUserProfile" in client && typeof client.fetchUserProfile === "function";
3175
+ }
3176
+ var isProfileProviderOption = (option) => {
3177
+ if (!isValidProviderOption(option))
3178
+ return false;
3179
+ const provider = providers[option];
3180
+ return provider.profileRequest !== undefined;
3181
+ };
3182
+ function isRefreshableOAuth2Client(providerOrClient, maybeClient) {
3183
+ const client = maybeClient ?? providerOrClient;
3184
+ if (maybeClient !== undefined && (typeof providerOrClient !== "string" || !isRefreshableProviderOption(providerOrClient))) {
3185
+ return false;
3186
+ }
3187
+ return typeof client === "object" && client !== null && "refreshAccessToken" in client && typeof client.refreshAccessToken === "function";
3188
+ }
3184
3189
  var isRefreshableProviderOption = (option) => {
3185
3190
  if (!isValidProviderOption(option))
3186
3191
  return false;
3187
3192
  const provider = providers[option];
3188
3193
  return provider.isRefreshable;
3189
3194
  };
3190
- var isRevocableOAuth2Client = (providerName, _client) => isRevocableProviderOption(providerName);
3195
+ function isRevocableOAuth2Client(providerOrClient, maybeClient) {
3196
+ const client = maybeClient ?? providerOrClient;
3197
+ if (maybeClient !== undefined && (typeof providerOrClient !== "string" || !isRevocableProviderOption(providerOrClient))) {
3198
+ return false;
3199
+ }
3200
+ return typeof client === "object" && client !== null && "resolveRevocationInput" in client && typeof client.resolveRevocationInput === "function" && "revokeToken" in client && typeof client.revokeToken === "function";
3201
+ }
3191
3202
  var isRevocableProviderOption = (option) => {
3192
3203
  if (!isValidProviderOption(option))
3193
3204
  return false;
@@ -3201,6 +3212,14 @@ var isScopeRequiredProviderOption = (option) => {
3201
3212
  return provider.scopeRequired;
3202
3213
  };
3203
3214
  var isValidProviderOption = (option) => Object.hasOwn(providers, option);
3215
+ var readPath = (value, path) => path.reduce((cursor, key) => cursor && typeof cursor === "object" ? Reflect.get(cursor, key) : undefined, value);
3216
+ var assertWithingsSuccess = (value) => {
3217
+ if (!isObject(value) || value.status !== 0) {
3218
+ const status = isObject(value) ? value.status : "invalid response";
3219
+ const detail = isObject(value) && typeof value.error === "string" ? `: ${value.error}` : "";
3220
+ throw new Error(`Withings request failed (${String(status)})${detail}`);
3221
+ }
3222
+ };
3204
3223
  var createOAuth2FetchError = async (response) => {
3205
3224
  const clone = response.clone();
3206
3225
  const prefix = `HTTP ${response.status} ${response.statusText} for ${response.url}`;
@@ -3234,16 +3253,27 @@ var createOAuth2Request = ({
3234
3253
  }
3235
3254
  oauthHeaders.set("Authorization", `Basic ${encodeBase64(`${clientId}:${clientSecret}`)}`);
3236
3255
  }
3256
+ if (body === undefined && authIn !== "body") {
3257
+ return new Request(url, {
3258
+ headers: oauthHeaders,
3259
+ method: "POST"
3260
+ });
3261
+ }
3237
3262
  if (encoding === "application/json") {
3238
3263
  oauthHeaders.set("Content-Type", "application/json");
3264
+ const jsonBody = body instanceof URLSearchParams ? Object.fromEntries(body.entries()) : { ...body };
3265
+ if (authIn === "body")
3266
+ jsonBody.client_id = clientId;
3267
+ if (authIn === "body" && clientSecret)
3268
+ jsonBody.client_secret = clientSecret;
3239
3269
  return new Request(url, {
3240
- body: JSON.stringify(body),
3270
+ body: JSON.stringify(jsonBody),
3241
3271
  headers: oauthHeaders,
3242
3272
  method: "POST"
3243
3273
  });
3244
3274
  }
3245
3275
  oauthHeaders.set("Content-Type", "application/x-www-form-urlencoded");
3246
- const entries = body instanceof URLSearchParams ? Array.from(body.entries()) : Object.entries(body).filter((entry) => typeof entry[1] === "string");
3276
+ const entries = body instanceof URLSearchParams ? Array.from(body.entries()) : Object.entries(body ?? {}).filter((entry) => typeof entry[1] === "string");
3247
3277
  const params = new URLSearchParams(entries);
3248
3278
  if (authIn === "body") {
3249
3279
  params.set("client_id", clientId);
@@ -3289,25 +3319,31 @@ var encodeBase64 = (input) => {
3289
3319
  }
3290
3320
  return btoa(raw);
3291
3321
  };
3292
- var getWithingsProps = async (config) => {
3322
+ var getWithingsSignatureParams = async (config, action) => {
3293
3323
  const timestamp = Math.floor(Date.now() / 1000);
3294
- const signature = `getnonce,${config.clientId},${timestamp}`;
3295
- const hashedSignature = await hmacSha256(signature, config.clientSecret);
3324
+ const nonceSignature = await hmacSha256(`getnonce,${config.clientId},${timestamp}`, config.clientSecret);
3296
3325
  const nonceUrl = new URL("https://wbsapi.withings.net/v2/signature");
3297
3326
  nonceUrl.searchParams.set("action", "getnonce");
3298
3327
  nonceUrl.searchParams.set("client_id", config.clientId);
3299
3328
  nonceUrl.searchParams.set("timestamp", timestamp.toString());
3300
- nonceUrl.searchParams.set("signature", hashedSignature);
3329
+ nonceUrl.searchParams.set("signature", nonceSignature);
3301
3330
  const nonceTarget = nonceUrl.toString();
3302
3331
  const nonceResponse = await fetch(nonceTarget, { method: "POST" });
3332
+ if (!nonceResponse.ok) {
3333
+ throw await createOAuth2FetchError(nonceResponse);
3334
+ }
3303
3335
  const nonceData = await nonceResponse.json();
3304
- if (nonceData.status === 0) {
3305
- return {
3306
- hashedSignature,
3307
- nonce: nonceData.body.nonce
3308
- };
3336
+ if (!isObject(nonceData) || nonceData.status !== 0 || !isObject(nonceData.body) || typeof nonceData.body.nonce !== "string" || nonceData.body.nonce.length === 0) {
3337
+ throw new Error("Withings returned an invalid nonce response");
3309
3338
  }
3310
- return;
3339
+ const { nonce } = nonceData.body;
3340
+ const signature = await hmacSha256(`${action},${config.clientId},${nonce}`, config.clientSecret);
3341
+ return {
3342
+ action,
3343
+ client_id: config.clientId,
3344
+ nonce,
3345
+ signature
3346
+ };
3311
3347
  };
3312
3348
  var hmacSha256 = async (message, secret) => {
3313
3349
  const encoder = new TextEncoder;
@@ -3315,15 +3351,53 @@ var hmacSha256 = async (message, secret) => {
3315
3351
  const sigBuffer = await crypto.subtle.sign("HMAC", key, encoder.encode(message));
3316
3352
  return Array.from(new Uint8Array(sigBuffer)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
3317
3353
  };
3354
+ var parseOAuth2TokenResponse = (value, accessTokenPath) => {
3355
+ if (!isObject(value)) {
3356
+ throw new Error("OAuth token endpoint returned a non-object response");
3357
+ }
3358
+ const oauthError = Reflect.get(value, "error");
3359
+ if (typeof oauthError === "string" && oauthError.length > 0) {
3360
+ throw new Error(`OAuth token exchange failed: ${oauthError}`);
3361
+ }
3362
+ const response = { ...value };
3363
+ const nestedToken = accessTokenPath ? readPath(value, accessTokenPath) : undefined;
3364
+ if (typeof nestedToken === "string" && nestedToken.length > 0) {
3365
+ response.access_token = nestedToken;
3366
+ }
3367
+ if (typeof response.access_token !== "string" || response.access_token.length === 0) {
3368
+ throw new Error("OAuth token endpoint returned no access_token");
3369
+ }
3370
+ for (const key of ["refresh_token", "token_type", "scope", "id_token"]) {
3371
+ const field = response[key];
3372
+ if (field !== undefined && typeof field !== "string") {
3373
+ throw new Error(`OAuth token endpoint returned invalid ${key}: expected string`);
3374
+ }
3375
+ }
3376
+ const expiresIn = response.expires_in;
3377
+ if (typeof expiresIn === "string" && expiresIn.trim() !== "") {
3378
+ response.expires_in = Number(expiresIn);
3379
+ }
3380
+ if (response.expires_in !== undefined && (typeof response.expires_in !== "number" || !Number.isFinite(response.expires_in) || response.expires_in < 0)) {
3381
+ throw new Error("OAuth token endpoint returned invalid expires_in: expected a non-negative number");
3382
+ }
3383
+ return response;
3384
+ };
3385
+ var readIdentityKey = (value, key) => {
3386
+ if (Array.isArray(value)) {
3387
+ if (!/^\d+$/.test(key)) {
3388
+ throw new Error(`Invalid identity data shape: expected an array index, got ${key}`);
3389
+ }
3390
+ return value[Number(key)];
3391
+ }
3392
+ if (!isObject(value)) {
3393
+ throw new Error(`Invalid identity data shape: expected object, got ${typeof value}`);
3394
+ }
3395
+ return value[key];
3396
+ };
3318
3397
  var extractPropFromIdentity = (identity, keys, propType) => {
3319
3398
  let value = identity;
3320
3399
  for (const key of keys) {
3321
- if (Array.isArray(value))
3322
- value = value[Number(key)];
3323
- if (!isObject(value)) {
3324
- throw new Error(`Invalid identity data shape: expected object, got ${typeof value}`);
3325
- }
3326
- value = value[key];
3400
+ value = readIdentityKey(value, key);
3327
3401
  }
3328
3402
  if (propType !== undefined && !isExpectedType(value, propType)) {
3329
3403
  throw new Error(`Invalid identity data shape: expected ${propType}, got ${typeof value}`);
@@ -3358,6 +3432,13 @@ var normalizeProviderIdentity = ({
3358
3432
  const normalizedIdentity = structuredClone(identity);
3359
3433
  return setPropInIdentity(normalizedIdentity, canonicalKeys, subject);
3360
3434
  };
3435
+ var DAYS_IN_APPLE_CLIENT_SECRET_LIFETIME = 180;
3436
+ var HOURS_PER_DAY = 24;
3437
+ var MINUTES_PER_HOUR = 60;
3438
+ var SECONDS_PER_MINUTE = 60;
3439
+ var APPLE_CLIENT_SECRET_LIFETIME_SECONDS = SECONDS_PER_MINUTE * MINUTES_PER_HOUR * HOURS_PER_DAY * DAYS_IN_APPLE_CLIENT_SECRET_LIFETIME;
3440
+ var APPLE_ISSUER = "https://appleid.apple.com";
3441
+ var MILLISECONDS_PER_SECOND = 1000;
3361
3442
  var createS256CodeChallenge = async (codeVerifier) => {
3362
3443
  const data = new TextEncoder().encode(codeVerifier);
3363
3444
  const hashBuffer = await crypto.subtle.digest("SHA-256", data);
@@ -3370,20 +3451,40 @@ var createRandomBase64UrlGenerator = (length) => () => {
3370
3451
  var generateCodeVerifier = createRandomBase64UrlGenerator(NUM_GENERATOR_BYTES);
3371
3452
  var generateState = createRandomBase64UrlGenerator(NUM_GENERATOR_BYTES);
3372
3453
  var base64Url = (input) => encodeBase64(input).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
3454
+ var encodeJwtPart = (value) => base64Url(new TextEncoder().encode(JSON.stringify(value)));
3455
+ var createAppleClientSecret = async (credentials) => {
3456
+ const issuedAt = Math.floor(Date.now() / MILLISECONDS_PER_SECOND);
3457
+ const header = encodeJwtPart({
3458
+ alg: "ES256",
3459
+ kid: credentials.keyId,
3460
+ typ: "JWT"
3461
+ });
3462
+ const payload = encodeJwtPart({
3463
+ aud: APPLE_ISSUER,
3464
+ exp: issuedAt + APPLE_CLIENT_SECRET_LIFETIME_SECONDS,
3465
+ iat: issuedAt,
3466
+ iss: credentials.teamId,
3467
+ sub: credentials.clientId
3468
+ });
3469
+ const signingInput = `${header}.${payload}`;
3470
+ const privateKey = await crypto.subtle.importKey("pkcs8", Uint8Array.from(credentials.pkcs8PrivateKey), { name: "ECDSA", namedCurve: "P-256" }, false, ["sign"]);
3471
+ const signature = await crypto.subtle.sign({ hash: "SHA-256", name: "ECDSA" }, privateKey, new TextEncoder().encode(signingInput));
3472
+ return `${signingInput}.${base64Url(signature)}`;
3473
+ };
3373
3474
  var ALG_ES256 = "ES256";
3374
3475
  var ALG_RS256 = "RS256";
3375
3476
  var CLOCK_SKEW_SECONDS = 60;
3376
3477
  var DEFAULT_SCOPES = ["openid", "email", "profile"];
3377
3478
  var JWKS_REFETCH_COOLDOWN_MS = 60000;
3378
3479
  var JWT_SEGMENT_COUNT = 3;
3379
- var MILLISECONDS_PER_SECOND = 1000;
3480
+ var MILLISECONDS_PER_SECOND2 = 1000;
3380
3481
  var trimTrailingSlash = (value) => value.endsWith("/") ? value.slice(0, -1) : value;
3381
3482
  var fetchJson = async (url) => {
3382
3483
  const response = await fetch(url, {
3383
3484
  headers: { accept: "application/json" }
3384
3485
  });
3385
3486
  if (!response.ok) {
3386
- throw new Error(`Request to ${url} failed with status ${response.status}`);
3487
+ throw await createOAuth2FetchError(response);
3387
3488
  }
3388
3489
  return response.json();
3389
3490
  };
@@ -3414,11 +3515,14 @@ var verifySignature = (key, alg, signingInput, signature) => {
3414
3515
  var selectKey = (jwks, kid) => jwks.find((jwk) => kid === undefined || jwk.kid === kid);
3415
3516
  var assertClaims = (payload, expected) => {
3416
3517
  const aud = Reflect.get(payload, "aud");
3518
+ const azp = Reflect.get(payload, "azp");
3417
3519
  const exp = Reflect.get(payload, "exp");
3520
+ const iat = Reflect.get(payload, "iat");
3418
3521
  const iss = Reflect.get(payload, "iss");
3522
+ const nbf = Reflect.get(payload, "nbf");
3419
3523
  const sub = Reflect.get(payload, "sub");
3420
3524
  const audiences = Array.isArray(aud) ? aud : [aud];
3421
- const nowSeconds = Math.floor(Date.now() / MILLISECONDS_PER_SECOND);
3525
+ const nowSeconds = Math.floor(Date.now() / MILLISECONDS_PER_SECOND2);
3422
3526
  if (iss !== expected.issuer) {
3423
3527
  throw new Error('id_token "iss" does not match the provider issuer');
3424
3528
  }
@@ -3428,9 +3532,24 @@ var assertClaims = (payload, expected) => {
3428
3532
  if (!audiences.includes(expected.audience)) {
3429
3533
  throw new Error('id_token "aud" does not include the client id');
3430
3534
  }
3535
+ if (audiences.some((audience) => typeof audience !== "string") || typeof aud !== "string" && !Array.isArray(aud)) {
3536
+ throw new Error('id_token "aud" must be a string or string array');
3537
+ }
3538
+ if (audiences.length > 1 && (typeof azp !== "string" || azp !== expected.audience)) {
3539
+ throw new Error('id_token with multiple audiences requires matching "azp"');
3540
+ }
3431
3541
  if (typeof exp !== "number" || exp + CLOCK_SKEW_SECONDS < nowSeconds) {
3432
3542
  throw new Error("id_token has expired");
3433
3543
  }
3544
+ if (typeof iat !== "number") {
3545
+ throw new Error('id_token is missing numeric "iat"');
3546
+ }
3547
+ if (iat > nowSeconds + CLOCK_SKEW_SECONDS) {
3548
+ throw new Error('id_token "iat" is in the future');
3549
+ }
3550
+ if (nbf !== undefined && (typeof nbf !== "number" || nbf > nowSeconds + CLOCK_SKEW_SECONDS)) {
3551
+ throw new Error("id_token is not active yet");
3552
+ }
3434
3553
  if (expected.nonce !== undefined && Reflect.get(payload, "nonce") !== expected.nonce) {
3435
3554
  throw new Error('id_token "nonce" does not match');
3436
3555
  }
@@ -3557,9 +3676,9 @@ var createOIDCClient = async (config) => {
3557
3676
  method: "POST"
3558
3677
  });
3559
3678
  if (!response.ok) {
3560
- throw new Error(`OIDC token request failed with status ${response.status}`);
3679
+ throw await createOAuth2FetchError(response);
3561
3680
  }
3562
- const tokens = await response.json();
3681
+ const tokens = parseOAuth2TokenResponse(await response.json());
3563
3682
  return tokens;
3564
3683
  };
3565
3684
  const verifyToken = async (idToken, options) => {
@@ -3605,20 +3724,26 @@ var createOIDCClient = async (config) => {
3605
3724
  };
3606
3725
  var oidcProviderOptions = Object.keys(providers).filter(isOIDCProviderOption);
3607
3726
  var pkceProviderOptions = Object.keys(providers).filter(isPKCEProviderOption);
3727
+ var profileProviderOptions = Object.keys(providers).filter(isProfileProviderOption);
3608
3728
  var providerOptions = Object.keys(providers).filter(isValidProviderOption);
3609
3729
  var refreshableProviderOptions = Object.keys(providers).filter(isRefreshableProviderOption);
3610
3730
  var revocableProviderOptions = Object.keys(providers).filter(isRevocableProviderOption);
3611
3731
  var scopeRequiredProviderOptions = Object.keys(providers).filter(isScopeRequiredProviderOption);
3612
- var readPath = (value, path) => path.reduce((cursor, key) => cursor && typeof cursor === "object" ? Reflect.get(cursor, key) : undefined, value);
3613
3732
  var buildOAuth2Client = async (meta, config) => {
3614
3733
  const isConfigPropertyFunction = (cfgProp) => typeof cfgProp === "function";
3615
3734
  const resolveConfigProp = async (cfgProp) => {
3616
3735
  const result = isConfigPropertyFunction(cfgProp) ? cfgProp(config) : cfgProp;
3617
3736
  return result;
3618
3737
  };
3738
+ const resolveClientSecret = async () => {
3739
+ if (meta.createClientSecret) {
3740
+ return resolveConfigProp(meta.createClientSecret);
3741
+ }
3742
+ return hasClientSecret(config) ? config.clientSecret : undefined;
3743
+ };
3619
3744
  const authorizationUrl = await resolveConfigProp(meta.authorizationUrl);
3620
3745
  const tokenUrl = await resolveConfigProp(meta.tokenRequest.url);
3621
- return {
3746
+ const client = {
3622
3747
  async createAuthorizationUrl(opts) {
3623
3748
  const { state, scope = [], searchParams = [], codeVerifier } = opts;
3624
3749
  const url = new URL(authorizationUrl);
@@ -3639,7 +3764,7 @@ var buildOAuth2Client = async (meta, config) => {
3639
3764
  url.searchParams.set("code_challenge_method", meta.PKCEMethod);
3640
3765
  url.searchParams.set("code_challenge", codeChallenge);
3641
3766
  }
3642
- Object.entries(resolveConfigProp(meta.createAuthorizationURLSearchParams) ?? {}).forEach(([key, value]) => url.searchParams.set(key, value));
3767
+ Object.entries(await resolveConfigProp(meta.createAuthorizationURLSearchParams) ?? {}).forEach(([key, value]) => url.searchParams.set(key, value));
3643
3768
  searchParams.forEach(([key, value]) => url.searchParams.set(key, value));
3644
3769
  return url;
3645
3770
  },
@@ -3672,7 +3797,7 @@ var buildOAuth2Client = async (meta, config) => {
3672
3797
  if (authIn === "header") {
3673
3798
  profileHeaders.Authorization = `Bearer ${accessToken}`;
3674
3799
  } else if (authIn === "path") {
3675
- endpoint.pathname = `${endpoint.pathname.replace(/\/+$/, "")}/${accessToken}`;
3800
+ endpoint.pathname = `${endpoint.pathname.replace(/\/+$/, "")}/${encodeURIComponent(accessToken)}`;
3676
3801
  } else {
3677
3802
  endpoint.searchParams.append("access_token", accessToken);
3678
3803
  }
@@ -3693,9 +3818,8 @@ var buildOAuth2Client = async (meta, config) => {
3693
3818
  params.set("grant_type", "refresh_token");
3694
3819
  params.set("refresh_token", refreshToken);
3695
3820
  const { clientId } = config;
3696
- let clientSecretValue;
3697
- if (hasClientSecret(config)) {
3698
- clientSecretValue = config.clientSecret;
3821
+ const clientSecretValue = await resolveClientSecret();
3822
+ if (clientSecretValue) {
3699
3823
  params.set("client_id", clientId);
3700
3824
  params.set("client_secret", clientSecretValue);
3701
3825
  }
@@ -3710,60 +3834,99 @@ var buildOAuth2Client = async (meta, config) => {
3710
3834
  const response = await fetch(request);
3711
3835
  if (!response.ok)
3712
3836
  throw await createOAuth2FetchError(response);
3713
- return response.json();
3837
+ return parseOAuth2TokenResponse(await response.json());
3838
+ },
3839
+ resolveRevocationInput(context) {
3840
+ const { revocationRequest } = meta;
3841
+ if (!revocationRequest) {
3842
+ throw new Error("Token revocation not defined for this provider");
3843
+ }
3844
+ const inputSource = revocationRequest.inputSource ?? "accessToken";
3845
+ const input = context[inputSource];
3846
+ if (input === undefined) {
3847
+ throw new Error(`Revocation requires ${inputSource}, but it was not provided`);
3848
+ }
3849
+ const expectsNumber = revocationRequest.authIn !== "header" && revocationRequest.inputType === "number";
3850
+ if (expectsNumber && (typeof input !== "number" || !Number.isFinite(input))) {
3851
+ throw new TypeError("This provider requires a numeric revocation input");
3852
+ }
3853
+ if (!expectsNumber && typeof input !== "string") {
3854
+ throw new TypeError("This provider requires a string revocation input");
3855
+ }
3856
+ return input;
3714
3857
  },
3715
- async revokeToken(token) {
3858
+ async revokeToken(input) {
3716
3859
  const { revocationRequest } = meta;
3717
3860
  if (!revocationRequest) {
3718
3861
  throw new Error("Token revocation not defined for this provider");
3719
3862
  }
3720
- const { url, authIn, body, headers, tokenParamName } = revocationRequest;
3863
+ if (revocationRequest.authIn !== "header" && revocationRequest.inputType === "number" && (typeof input !== "number" || !Number.isFinite(input))) {
3864
+ throw new TypeError("This provider requires a numeric revocation input");
3865
+ }
3866
+ const {
3867
+ url,
3868
+ authIn,
3869
+ body,
3870
+ encoding,
3871
+ headers,
3872
+ includeClientCredentials = true,
3873
+ tokenParamName,
3874
+ validateResponse
3875
+ } = revocationRequest;
3721
3876
  const endpoint = await resolveConfigProp(url);
3722
3877
  const resolvedBody = await resolveConfigProp(body);
3723
- const revocationBody = new URLSearchParams(resolvedBody);
3878
+ const revocationBody = resolvedBody === undefined ? undefined : new URLSearchParams(resolvedBody);
3724
3879
  const revocationHeaders = new Headers(headers && await resolveConfigProp(headers));
3725
3880
  const { clientId } = config;
3726
- const clientSecret = hasClientSecret(config) ? config.clientSecret : undefined;
3881
+ const clientSecret = await resolveClientSecret();
3727
3882
  let request;
3728
3883
  if (authIn === "body") {
3729
- revocationBody.set(tokenParamName, token);
3730
- revocationBody.set("client_id", clientId);
3731
- if (clientSecret)
3732
- revocationBody.set("client_secret", clientSecret);
3884
+ const bodyWithToken = revocationBody ?? new URLSearchParams;
3885
+ bodyWithToken.set(tokenParamName, String(input));
3886
+ const hasAuthorizationHeader = revocationHeaders.has("Authorization");
3887
+ if (includeClientCredentials && !hasAuthorizationHeader)
3888
+ bodyWithToken.set("client_id", clientId);
3889
+ if (includeClientCredentials && !hasAuthorizationHeader && clientSecret)
3890
+ bodyWithToken.set("client_secret", clientSecret);
3733
3891
  request = createOAuth2Request({
3734
- authIn: "body",
3735
- body: revocationBody,
3892
+ authIn: hasAuthorizationHeader || !includeClientCredentials ? "query" : "body",
3893
+ body: bodyWithToken,
3736
3894
  clientId,
3737
3895
  clientSecret,
3738
- encoding: "application/x-www-form-urlencoded",
3896
+ encoding,
3739
3897
  headers: revocationHeaders,
3740
3898
  url: endpoint.toString()
3741
3899
  });
3742
3900
  } else if (authIn === "header") {
3743
- revocationHeaders.set("Authorization", `Bearer ${token}`);
3901
+ revocationHeaders.set("Authorization", `Bearer ${String(input)}`);
3744
3902
  request = createOAuth2Request({
3745
- authIn: "header",
3903
+ authIn: "query",
3746
3904
  body: revocationBody,
3747
3905
  clientId,
3748
- clientSecret,
3749
- encoding: "application/x-www-form-urlencoded",
3906
+ encoding,
3750
3907
  headers: revocationHeaders,
3751
3908
  url: endpoint.toString()
3752
3909
  });
3753
3910
  } else {
3911
+ const queryEndpoint = new URL(endpoint);
3912
+ queryEndpoint.searchParams.set(tokenParamName, String(input));
3754
3913
  request = createOAuth2Request({
3755
3914
  authIn: "query",
3756
3915
  body: revocationBody,
3757
3916
  clientId,
3758
- clientSecret,
3759
- encoding: "application/x-www-form-urlencoded",
3917
+ encoding,
3760
3918
  headers: revocationHeaders,
3761
- url: `${endpoint.toString()}?${tokenParamName}=${token}`
3919
+ url: queryEndpoint.toString()
3762
3920
  });
3763
3921
  }
3764
3922
  const response = await fetch(request);
3765
3923
  if (!response.ok)
3766
3924
  throw await createOAuth2FetchError(response);
3925
+ if (validateResponse) {
3926
+ await validateResponse(await response.json().catch(() => {
3927
+ return;
3928
+ }));
3929
+ }
3767
3930
  },
3768
3931
  async validateAuthorizationCode(opts) {
3769
3932
  const { code, codeVerifier } = opts;
@@ -3789,32 +3952,27 @@ var buildOAuth2Client = async (meta, config) => {
3789
3952
  authIn,
3790
3953
  body: payload,
3791
3954
  clientId: config.clientId,
3792
- clientSecret: hasClientSecret(config) ? config.clientSecret : undefined,
3955
+ clientSecret: await resolveClientSecret(),
3793
3956
  encoding,
3794
3957
  url: tokenUrl
3795
3958
  });
3796
3959
  const response = await fetch(request);
3797
3960
  if (!response.ok)
3798
3961
  throw await createOAuth2FetchError(response);
3799
- const tokenResponse = await response.json();
3800
- if (!tokenResponse || typeof tokenResponse !== "object") {
3801
- throw new Error("OAuth token endpoint returned a non-object response");
3802
- }
3803
- const oauthError = Reflect.get(tokenResponse, "error");
3804
- if (typeof oauthError === "string" && oauthError.length > 0) {
3805
- throw new Error(`OAuth token exchange failed: ${oauthError}`);
3806
- }
3807
- const nestedToken = meta.accessTokenPath ? readPath(tokenResponse, meta.accessTokenPath) : undefined;
3808
- if (typeof nestedToken === "string" && nestedToken.length > 0 && tokenResponse && typeof tokenResponse === "object") {
3809
- tokenResponse.access_token = nestedToken;
3810
- }
3811
- const accessToken = Reflect.get(tokenResponse, "access_token");
3812
- if (typeof accessToken !== "string" || accessToken.length === 0) {
3813
- throw new Error("OAuth token endpoint returned no access_token");
3814
- }
3815
- return tokenResponse;
3962
+ return parseOAuth2TokenResponse(await response.json(), meta.accessTokenPath);
3816
3963
  }
3817
3964
  };
3965
+ if (!meta.profileRequest) {
3966
+ Reflect.deleteProperty(client, "fetchUserProfile");
3967
+ }
3968
+ if (!meta.isRefreshable) {
3969
+ Reflect.deleteProperty(client, "refreshAccessToken");
3970
+ }
3971
+ if (!meta.revocationRequest) {
3972
+ Reflect.deleteProperty(client, "resolveRevocationInput");
3973
+ Reflect.deleteProperty(client, "revokeToken");
3974
+ }
3975
+ return client;
3818
3976
  };
3819
3977
  var createCustomOAuth2Client = (providerConfig, credentials) => buildOAuth2Client(providerConfig, credentials);
3820
3978
  var createOAuth2Client = (providerName, config) => buildOAuth2Client(providers[providerName], config);
@@ -5572,7 +5730,15 @@ var instantiateUserSession = async ({
5572
5730
  providerInstance,
5573
5731
  tokenResponse
5574
5732
  });
5575
- const { accessToken, refreshToken, userIdentity } = authorization;
5733
+ const {
5734
+ accessToken,
5735
+ oauthSubject: resolvedOAuthSubject,
5736
+ refreshToken,
5737
+ userIdentity
5738
+ } = authorization;
5739
+ const providerMeta = providerConfiguration ?? (isValidProviderOption(authProvider) ? providers[authProvider] : undefined);
5740
+ const extractedSubject = providerMeta ? extractPropFromIdentity(userIdentity, providerMeta.subject, providerMeta.subjectType) : Reflect.get(userIdentity, "sub");
5741
+ const oauthSubject = resolvedOAuthSubject ?? (typeof extractedSubject === "string" || typeof extractedSubject === "number" ? extractedSubject : undefined);
5576
5742
  const userSession = validateSession({ session, user_session_id });
5577
5743
  const userSessionId = getUserSessionId({
5578
5744
  cookieSecure,
@@ -5589,6 +5755,7 @@ var instantiateUserSession = async ({
5589
5755
  accessToken,
5590
5756
  authenticatedAt: Date.now(),
5591
5757
  expiresAt: Date.now() + sessionDurationMs,
5758
+ oauthSubject,
5592
5759
  refreshToken,
5593
5760
  user
5594
5761
  };
@@ -5598,6 +5765,7 @@ var instantiateUserSession = async ({
5598
5765
  if (existingUnregistered) {
5599
5766
  existingUnregistered.accessToken = accessToken;
5600
5767
  existingUnregistered.expiresAt = Date.now() + unregisteredSessionDurationMs;
5768
+ existingUnregistered.oauthSubject = oauthSubject;
5601
5769
  existingUnregistered.refreshToken = refreshToken;
5602
5770
  existingUnregistered.userIdentity = userIdentity;
5603
5771
  return response;
@@ -5605,6 +5773,7 @@ var instantiateUserSession = async ({
5605
5773
  unregisteredSession[userSessionId] = {
5606
5774
  accessToken,
5607
5775
  expiresAt: Date.now() + unregisteredSessionDurationMs,
5776
+ oauthSubject,
5608
5777
  refreshToken,
5609
5778
  userIdentity
5610
5779
  };
@@ -5653,6 +5822,9 @@ var resolveOAuthAuthorization = async ({
5653
5822
  accessToken = readOptionalString(withingsBody, "access_token") ?? accessToken;
5654
5823
  refreshToken = readOptionalString(withingsBody, "refresh_token") ?? refreshToken;
5655
5824
  } else {
5825
+ if (!isProfileOAuth2Client(providerInstance)) {
5826
+ throw new Error(`Provider "${authProvider}" returned no identity and has no profile endpoint`);
5827
+ }
5656
5828
  userIdentity = normalizeProviderIdentity({
5657
5829
  identity: await providerInstance.fetchUserProfile(accessToken),
5658
5830
  providerConfiguration: meta,
@@ -5660,9 +5832,14 @@ var resolveOAuthAuthorization = async ({
5660
5832
  });
5661
5833
  }
5662
5834
  const tokenType = Reflect.get(tokenResponse, "token_type");
5835
+ const oauthSubject = extractPropFromIdentity(userIdentity, meta.subject, meta.subjectType);
5836
+ if (typeof oauthSubject !== "string" && typeof oauthSubject !== "number") {
5837
+ throw new Error(`Provider "${authProvider}" returned an invalid OAuth subject`);
5838
+ }
5663
5839
  return {
5664
5840
  accessToken,
5665
5841
  expiresAt: resolveOAuthTokenExpiresAt(tokenResponse, now),
5842
+ oauthSubject,
5666
5843
  refreshToken,
5667
5844
  tokenType: typeof tokenType === "string" ? tokenType : undefined,
5668
5845
  userIdentity
@@ -7610,10 +7787,10 @@ var exchangeBackchannelAuth = async ({
7610
7787
  init_constants();
7611
7788
  var CLIENT_ASSERTION_TYPE = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
7612
7789
  var MAX_ASSERTION_LIFETIME_MINUTES = 5;
7613
- var SECONDS_PER_MINUTE = 60;
7614
- var MAX_ASSERTION_LIFETIME_MS = MAX_ASSERTION_LIFETIME_MINUTES * SECONDS_PER_MINUTE * MILLISECONDS_IN_A_SECOND;
7790
+ var SECONDS_PER_MINUTE2 = 60;
7791
+ var MAX_ASSERTION_LIFETIME_MS = MAX_ASSERTION_LIFETIME_MINUTES * SECONDS_PER_MINUTE2 * MILLISECONDS_IN_A_SECOND;
7615
7792
  var jwksCache = new Map;
7616
- var JWKS_CACHE_TTL_MS = SECONDS_PER_MINUTE * MILLISECONDS_IN_A_SECOND;
7793
+ var JWKS_CACHE_TTL_MS = SECONDS_PER_MINUTE2 * MILLISECONDS_IN_A_SECOND;
7617
7794
  var JWKS_FETCH_TIMEOUT_SECONDS = 5;
7618
7795
  var JWKS_FETCH_TIMEOUT_MS = JWKS_FETCH_TIMEOUT_SECONDS * MILLISECONDS_IN_A_SECOND;
7619
7796
  var fetchJwksUri = async (jwksUri) => {
@@ -11170,6 +11347,7 @@ var callback = ({
11170
11347
  // src/routes/profile.ts
11171
11348
  import { Elysia as Elysia29, t as t22 } from "elysia";
11172
11349
  var profile = ({
11350
+ authSessionStore,
11173
11351
  clientProviders,
11174
11352
  profileRoute = "/oauth2/profile",
11175
11353
  onProfileSuccess,
@@ -11184,9 +11362,6 @@ var profile = ({
11184
11362
  if (auth_provider.value === undefined) {
11185
11363
  return status("Unauthorized", "No auth provider found");
11186
11364
  }
11187
- if (!isValidProviderOption(auth_provider.value)) {
11188
- return status("Unauthorized", "Invalid provider");
11189
- }
11190
11365
  if (user_session_id.value === undefined) {
11191
11366
  return status("Unauthorized", "No user session found");
11192
11367
  }
@@ -11199,7 +11374,14 @@ var profile = ({
11199
11374
  return status("Unauthorized", resolvedProvider.error);
11200
11375
  }
11201
11376
  const { clientName, providerInstance } = resolvedProvider.entry;
11202
- const userSession = session[user_session_id.value];
11377
+ if (!isProfileOAuth2Client(providerInstance)) {
11378
+ return status("Not Implemented", "Provider does not expose a profile endpoint");
11379
+ }
11380
+ const userSession = await loadSessionFromSource({
11381
+ authSessionStore,
11382
+ session,
11383
+ userSessionId: user_session_id.value
11384
+ });
11203
11385
  if (userSession === undefined) {
11204
11386
  return status("Unauthorized", "No user session found");
11205
11387
  }
@@ -11251,9 +11433,6 @@ var refresh = ({
11251
11433
  if (auth_provider.value === undefined) {
11252
11434
  return status("Unauthorized", "No auth provider found");
11253
11435
  }
11254
- if (!isValidProviderOption(auth_provider.value)) {
11255
- return status("Bad Request", "Invalid provider");
11256
- }
11257
11436
  if (user_session_id.value === undefined) {
11258
11437
  return status("Unauthorized", "No user session found");
11259
11438
  }
@@ -11275,7 +11454,7 @@ var refresh = ({
11275
11454
  return status("Unauthorized", "No user session found");
11276
11455
  }
11277
11456
  const { refreshToken } = userSession;
11278
- if (!isRefreshableOAuth2Client(auth_provider.value, providerInstance)) {
11457
+ if (!isRefreshableOAuth2Client(providerInstance)) {
11279
11458
  return status("Not Implemented", "Provider is not refreshable");
11280
11459
  }
11281
11460
  if (refreshToken === undefined) {
@@ -11335,9 +11514,6 @@ var revoke = ({
11335
11514
  if (auth_provider.value === undefined) {
11336
11515
  return status("Unauthorized", "No auth provider found");
11337
11516
  }
11338
- if (!isValidProviderOption(auth_provider.value)) {
11339
- return status("Bad Request", "Invalid provider");
11340
- }
11341
11517
  if (user_session_id.value === undefined) {
11342
11518
  return status("Unauthorized", "No user session found");
11343
11519
  }
@@ -11350,7 +11526,7 @@ var revoke = ({
11350
11526
  return status("Unauthorized", resolvedProvider.error);
11351
11527
  }
11352
11528
  const { clientName, providerInstance } = resolvedProvider.entry;
11353
- if (!isRevocableOAuth2Client(auth_provider.value, providerInstance)) {
11529
+ if (!isRevocableOAuth2Client(providerInstance)) {
11354
11530
  return status("Not Implemented", "Provider does not support revocation");
11355
11531
  }
11356
11532
  const userSession = await loadSessionFromSource({
@@ -11361,16 +11537,21 @@ var revoke = ({
11361
11537
  if (userSession === undefined) {
11362
11538
  return status("Unauthorized", "No user session found");
11363
11539
  }
11364
- const { accessToken } = userSession;
11540
+ const { accessToken, oauthSubject, refreshToken } = userSession;
11365
11541
  if (accessToken === undefined) {
11366
11542
  return status("Bad Request", "Session has no access token to revoke");
11367
11543
  }
11368
11544
  try {
11369
- await providerInstance.revokeToken(accessToken);
11545
+ const tokenToRevoke = providerInstance.resolveRevocationInput({
11546
+ accessToken,
11547
+ refreshToken,
11548
+ subject: oauthSubject
11549
+ });
11550
+ await providerInstance.revokeToken(tokenToRevoke);
11370
11551
  await onRevocationSuccess?.({
11371
11552
  authClient: clientName,
11372
11553
  authProvider: auth_provider.value,
11373
- tokenToRevoke: accessToken
11554
+ tokenToRevoke
11374
11555
  });
11375
11556
  return new Response("Token revoked", {
11376
11557
  status: 204
@@ -25210,6 +25391,7 @@ var authSessionsTable = pgTable("auth_sessions", {
25210
25391
  created_at: timestamp("created_at").notNull().defaultNow(),
25211
25392
  expires_at_ms: bigint("expires_at_ms", { mode: "number" }).notNull(),
25212
25393
  id: varchar("id", { length: 255 }).primaryKey(),
25394
+ oauth_subject_json: jsonb("oauth_subject_json").$type(),
25213
25395
  refresh_token: text("refresh_token"),
25214
25396
  updated_at: timestamp("updated_at").notNull().defaultNow(),
25215
25397
  user_json: jsonb("user_json").$type().notNull()
@@ -25219,6 +25401,7 @@ var authUnregisteredSessionsTable = pgTable("auth_unregistered_sessions", {
25219
25401
  created_at: timestamp("created_at").notNull().defaultNow(),
25220
25402
  expires_at_ms: bigint("expires_at_ms", { mode: "number" }).notNull(),
25221
25403
  id: varchar("id", { length: 255 }).primaryKey(),
25404
+ oauth_subject_json: jsonb("oauth_subject_json").$type(),
25222
25405
  refresh_token: text("refresh_token"),
25223
25406
  session_information_json: jsonb("session_information_json").$type(),
25224
25407
  updated_at: timestamp("updated_at").notNull().defaultNow(),
@@ -25236,12 +25419,14 @@ var toSessionData = (row, decodeUser) => ({
25236
25419
  accessToken: row.access_token ?? undefined,
25237
25420
  authenticatedAt: row.authenticated_at_ms ?? undefined,
25238
25421
  expiresAt: row.expires_at_ms,
25422
+ oauthSubject: row.oauth_subject_json ?? undefined,
25239
25423
  refreshToken: row.refresh_token ?? undefined,
25240
25424
  user: cloneUser(decodeUser(row.user_json))
25241
25425
  });
25242
25426
  var toUnregisteredSessionData = (row) => ({
25243
25427
  accessToken: row.access_token ?? undefined,
25244
25428
  expiresAt: row.expires_at_ms,
25429
+ oauthSubject: row.oauth_subject_json ?? undefined,
25245
25430
  refreshToken: row.refresh_token ?? undefined,
25246
25431
  sessionInformation: cloneRecord(row.session_information_json ?? undefined),
25247
25432
  userIdentity: cloneRecord(row.user_identity_json ?? undefined)
@@ -25286,6 +25471,7 @@ var createNeonAuthSessionStore = (databaseUrl, decodeUser) => {
25286
25471
  authenticated_at_ms: value.authenticatedAt ?? null,
25287
25472
  expires_at_ms: value.expiresAt,
25288
25473
  id,
25474
+ oauth_subject_json: value.oauthSubject ?? null,
25289
25475
  refresh_token: value.refreshToken ?? null,
25290
25476
  updated_at: new Date,
25291
25477
  user_json: value.user ?? {}
@@ -25294,6 +25480,7 @@ var createNeonAuthSessionStore = (databaseUrl, decodeUser) => {
25294
25480
  access_token: value.accessToken ?? null,
25295
25481
  authenticated_at_ms: value.authenticatedAt ?? null,
25296
25482
  expires_at_ms: value.expiresAt,
25483
+ oauth_subject_json: value.oauthSubject ?? null,
25297
25484
  refresh_token: value.refreshToken ?? null,
25298
25485
  updated_at: new Date,
25299
25486
  user_json: value.user ?? {}
@@ -25306,6 +25493,7 @@ var createNeonAuthSessionStore = (databaseUrl, decodeUser) => {
25306
25493
  access_token: value.accessToken ?? null,
25307
25494
  expires_at_ms: value.expiresAt,
25308
25495
  id,
25496
+ oauth_subject_json: value.oauthSubject ?? null,
25309
25497
  refresh_token: value.refreshToken ?? null,
25310
25498
  session_information_json: value.sessionInformation ?? null,
25311
25499
  updated_at: new Date,
@@ -25314,6 +25502,7 @@ var createNeonAuthSessionStore = (databaseUrl, decodeUser) => {
25314
25502
  set: {
25315
25503
  access_token: value.accessToken ?? null,
25316
25504
  expires_at_ms: value.expiresAt,
25505
+ oauth_subject_json: value.oauthSubject ?? null,
25317
25506
  refresh_token: value.refreshToken ?? null,
25318
25507
  session_information_json: value.sessionInformation ?? null,
25319
25508
  updated_at: new Date,
@@ -31353,6 +31542,7 @@ var sessionSchema = Type.Object({
31353
31542
  authenticatedAt: Type.Optional(Type.Number()),
31354
31543
  expiresAt: Type.Number(),
31355
31544
  impersonator: Type.Optional(impersonatorSchema),
31545
+ oauthSubject: Type.Optional(Type.Union([Type.String(), Type.Number()])),
31356
31546
  refreshToken: Type.Optional(Type.String()),
31357
31547
  samlLogout: Type.Optional(Type.Object({
31358
31548
  connectionId: Type.String(),
@@ -31364,6 +31554,7 @@ var sessionSchema = Type.Object({
31364
31554
  var unregisteredSessionSchema = Type.Object({
31365
31555
  accessToken: Type.Optional(Type.String()),
31366
31556
  expiresAt: Type.Number(),
31557
+ oauthSubject: Type.Optional(Type.Union([Type.String(), Type.Number()])),
31367
31558
  refreshToken: Type.Optional(Type.String()),
31368
31559
  sessionInformation: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
31369
31560
  userIdentity: Type.Optional(Type.Record(Type.String(), Type.Unknown()))
@@ -36948,30 +37139,40 @@ var JOURNAL_DDL = `CREATE TABLE IF NOT EXISTS "auth_migrations" (
36948
37139
  var isJournalRow = (value) => typeof value === "object" && value !== null && typeof Reflect.get(value, "id") === "string";
36949
37140
  var isBlockName = (value) => Object.hasOwn(blockMigrations, value);
36950
37141
  var allBlockNames = () => Object.keys(blockMigrations).filter(isBlockName);
36951
- var applyOne = async (pool, id, sql2, log) => {
36952
- await pool.query(sql2);
36953
- await pool.query(`INSERT INTO "auth_migrations" ("id", "applied_at_ms") VALUES ($1, $2)`, [id, Date.now()]);
37142
+ var applyOne = async (client, id, sql2, log) => {
37143
+ await client.query(sql2);
37144
+ await client.query(`INSERT INTO "auth_migrations" ("id", "applied_at_ms") VALUES ($1, $2)`, [id, Date.now()]);
36954
37145
  log(`apply ${id}`);
36955
37146
  };
36956
- var runOne = async (pool, id, sql2, applied, result, log) => {
37147
+ var runOne = async (client, id, sql2, applied, result, log) => {
36957
37148
  if (applied.has(id)) {
36958
37149
  result.skipped.push(id);
36959
37150
  log(`skip ${id}`);
36960
37151
  return;
36961
37152
  }
36962
- await applyOne(pool, id, sql2, log);
37153
+ await applyOne(client, id, sql2, log);
36963
37154
  result.applied.push(id);
36964
37155
  };
36965
37156
  var runMigrations = async ({
36966
37157
  blocks,
37158
+ client,
36967
37159
  databaseUrl,
36968
37160
  log = console.log
36969
37161
  }) => {
36970
- const pool = new Ln({ connectionString: databaseUrl });
37162
+ let ownedPool;
37163
+ let migrationClient;
37164
+ if (client !== undefined) {
37165
+ migrationClient = client;
37166
+ } else {
37167
+ if (databaseUrl === undefined)
37168
+ throw new Error("runMigrations requires databaseUrl or client");
37169
+ ownedPool = new Ln({ connectionString: databaseUrl });
37170
+ migrationClient = ownedPool;
37171
+ }
36971
37172
  const result = { applied: [], skipped: [] };
36972
37173
  try {
36973
- await pool.query(JOURNAL_DDL);
36974
- const journal = await pool.query(`SELECT "id" FROM "auth_migrations"`);
37174
+ await migrationClient.query(JOURNAL_DDL);
37175
+ const journal = await migrationClient.query(`SELECT "id" FROM "auth_migrations"`);
36975
37176
  const applied = new Set(journal.rows.filter(isJournalRow).map((row) => row.id));
36976
37177
  const selected = blocks ?? allBlockNames();
36977
37178
  const flat = selected.flatMap((block) => blockMigrations[block].migrations.map((migration) => ({
@@ -36980,10 +37181,10 @@ var runMigrations = async ({
36980
37181
  })));
36981
37182
  await flat.reduce(async (prior, item) => {
36982
37183
  await prior;
36983
- return runOne(pool, item.id, item.sql, applied, result, log);
37184
+ return runOne(migrationClient, item.id, item.sql, applied, result, log);
36984
37185
  }, Promise.resolve());
36985
37186
  } finally {
36986
- await pool.end();
37187
+ await ownedPool?.end();
36987
37188
  }
36988
37189
  return result;
36989
37190
  };
@@ -37016,6 +37217,14 @@ var oidcResourceAudienceMigration = {
37016
37217
  ].join(`
37017
37218
  `)
37018
37219
  };
37220
+ var sessionOAuthSubjectMigration = {
37221
+ id: "0002_oauth_subject",
37222
+ sql: [
37223
+ 'ALTER TABLE "auth_sessions" ADD COLUMN IF NOT EXISTS "oauth_subject_json" jsonb;',
37224
+ 'ALTER TABLE "auth_unregistered_sessions" ADD COLUMN IF NOT EXISTS "oauth_subject_json" jsonb;'
37225
+ ].join(`
37226
+ `)
37227
+ };
37019
37228
  var blockMigrations = {
37020
37229
  adaptive: initMigration("adaptive", [knownDevicesTable, loginHistoryTable]),
37021
37230
  agents: {
@@ -37084,10 +37293,16 @@ var blockMigrations = {
37084
37293
  portal: initMigration("portal", [setupSessionsTable]),
37085
37294
  roles: initMigration("roles", [rolesTable]),
37086
37295
  scim: initMigration("scim", [scimTokensTable]),
37087
- sessions: initMigration("sessions", [
37088
- authSessionsTable,
37089
- authUnregisteredSessionsTable
37090
- ]),
37296
+ sessions: {
37297
+ block: "sessions",
37298
+ migrations: [
37299
+ ...initMigration("sessions", [
37300
+ authSessionsTable,
37301
+ authUnregisteredSessionsTable
37302
+ ]).migrations,
37303
+ sessionOAuthSubjectMigration
37304
+ ]
37305
+ },
37091
37306
  sso: initMigration("sso", [ssoConnectionsTable, samlServiceProvidersTable]),
37092
37307
  vault: initMigration("vault", [vaultEntriesTable]),
37093
37308
  vc: initMigration("vc", [
@@ -37773,6 +37988,7 @@ var buildAuthApplications = async (configuration) => {
37773
37988
  resolveAuthIntent
37774
37989
  }),
37775
37990
  profile({
37991
+ authSessionStore,
37776
37992
  clientProviders,
37777
37993
  onProfileError,
37778
37994
  onProfileSuccess,
@@ -38042,5 +38258,5 @@ export {
38042
38258
  auth2 as auth
38043
38259
  };
38044
38260
 
38045
- //# debugId=56D8E62C3DDCAF8364756E2164756E21
38261
+ //# debugId=52D884157E2599DD64756E2164756E21
38046
38262
  //# sourceMappingURL=server.js.map