@hyper.authio/client 0.7.0 → 0.8.0

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
@@ -147,6 +147,8 @@ var AuthioAsymmetricAlgorithms = [
147
147
  "ES384",
148
148
  "ES512"
149
149
  ];
150
+ var AuthioHmacAlgorithms = ["HS256", "HS384", "HS512"];
151
+ var AuthioHmacMinimumSecretBytes = Object.freeze({ HS256: 32, HS384: 48, HS512: 64 });
150
152
  var AuthioDefaults = {
151
153
  DiscoveryPath: "/.well-known/openid-configuration",
152
154
  ProtectedResourceMetadataPath: "/.well-known/oauth-protected-resource",
@@ -278,6 +280,12 @@ var systemClock = {
278
280
  signal?.addEventListener("abort", onAbort, { once: true });
279
281
  })
280
282
  };
283
+ var AuthioTokenEndpointAuthMethods = [
284
+ "client_secret_basic",
285
+ "client_secret_post",
286
+ "private_key_jwt",
287
+ "none"
288
+ ];
281
289
  function resolveConnection(options) {
282
290
  const requireHttps = options.requireHttps ?? true;
283
291
  const issuer = resolveIssuer(options);
@@ -593,7 +601,9 @@ function createClientAuthenticator(settings, connection) {
593
601
  const clientId = settings.clientId?.trim();
594
602
  if (!clientId) throw new AuthioConfigurationError("The Authio clientId is required.");
595
603
  const hasKey = settings.clientPrivateKey !== void 0 || !!settings.clientPrivateKeyPath;
596
- const method = settings.clientAuthentication ?? (!settings.clientSecret && hasKey ? "private_key_jwt" : "client_secret_basic");
604
+ const method = settings.tokenEndpointAuthMethod ?? (settings.clientSecret ? "client_secret_basic" : hasKey ? "private_key_jwt" : "none");
605
+ if (!AuthioTokenEndpointAuthMethods.includes(method))
606
+ throw new AuthioConfigurationError(`The Authio tokenEndpointAuthMethod '${String(method)}' is not one of ${AuthioTokenEndpointAuthMethods.join(", ")}.`);
597
607
  if ((method === "client_secret_basic" || method === "client_secret_post") && !settings.clientSecret)
598
608
  throw new AuthioConfigurationError(`The Authio clientSecret is required with ${method}.`);
599
609
  if (method === "private_key_jwt" && !hasKey)
@@ -675,6 +685,7 @@ function createKeyLoader(settings) {
675
685
  var AuthioKeyManagementAlgorithms = ["RSA-OAEP", "RSA-OAEP-256"];
676
686
  var AuthioLegacyKeyManagementAlgorithms = ["RSA1_5"];
677
687
  var AuthioContentEncryptionAlgorithms = ["A128CBC-HS256", "A192CBC-HS384", "A256CBC-HS512"];
688
+ var AuthioSupportedContentEncryptionAlgorithms = [...AuthioContentEncryptionAlgorithms, "A128GCM", "A192GCM", "A256GCM"];
678
689
  var rsaAlgorithmIdentifier = [48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0];
679
690
  function isAuthioTokenEncrypted(token) {
680
691
  return typeof token === "string" && token.split(".").length === 5;
@@ -682,6 +693,13 @@ function isAuthioTokenEncrypted(token) {
682
693
  function createAuthioTokenDecrypter(key, options = {}) {
683
694
  const settings = typeof options === "string" ? { setting: options } : options;
684
695
  const setting = settings.setting ?? "clientEncryptionKey";
696
+ const keyManagementAlgorithms = resolveAllowlist(settings.encryptionAlgorithms, AuthioKeyManagementAlgorithms, AuthioKeyManagementAlgorithms, "encryptionAlgorithms");
697
+ const contentEncryptionAlgorithms = resolveAllowlist(
698
+ settings.encryptionMethods,
699
+ AuthioContentEncryptionAlgorithms,
700
+ AuthioSupportedContentEncryptionAlgorithms,
701
+ "encryptionMethods"
702
+ );
685
703
  const imported = /* @__PURE__ */ new Map();
686
704
  const importFor = (algorithm) => {
687
705
  let pending = imported.get(algorithm);
@@ -700,10 +718,16 @@ function createAuthioTokenDecrypter(key, options = {}) {
700
718
  "legacy_algorithm",
701
719
  settings.allowLegacyEncryptionAlgorithms ? "The token is encrypted with RSA1_5 (PKCS#1 v1.5), which Node and WebCrypto cannot decrypt even with allowLegacyEncryptionAlgorithms; register RSA-OAEP-256 as the client's encryption algorithm in Authio." : "The token is encrypted with the legacy RSA1_5 algorithm, which is refused; register RSA-OAEP-256 as the client's encryption algorithm in Authio."
702
720
  );
703
- if (!AuthioKeyManagementAlgorithms.includes(algorithm))
721
+ if (!keyManagementAlgorithms.includes(algorithm))
722
+ throw new AuthioTokenValidationError(
723
+ "decryption_failed",
724
+ `The token is encrypted with '${algorithm}', and encryptionAlgorithms accepts ${keyManagementAlgorithms.join(" or ")}.`
725
+ );
726
+ const method = contentMethodOf(token);
727
+ if (!contentEncryptionAlgorithms.includes(method))
704
728
  throw new AuthioTokenValidationError(
705
729
  "decryption_failed",
706
- `The token is encrypted with '${algorithm}'; Authio encrypts with ${AuthioKeyManagementAlgorithms.join(" or ")}.`
730
+ `The token's content is encrypted with '${method}', and encryptionMethods accepts ${contentEncryptionAlgorithms.join(" or ")}.`
707
731
  );
708
732
  if (key === void 0 || key === null || key === "")
709
733
  throw new AuthioTokenValidationError(
@@ -712,8 +736,8 @@ function createAuthioTokenDecrypter(key, options = {}) {
712
736
  );
713
737
  try {
714
738
  const { plaintext } = await compactDecrypt(token, (header) => importFor(header.alg), {
715
- keyManagementAlgorithms: [...AuthioKeyManagementAlgorithms],
716
- contentEncryptionAlgorithms: [...AuthioContentEncryptionAlgorithms]
739
+ keyManagementAlgorithms: [...keyManagementAlgorithms],
740
+ contentEncryptionAlgorithms: [...contentEncryptionAlgorithms]
717
741
  });
718
742
  return new TextDecoder().decode(plaintext);
719
743
  } catch (error) {
@@ -747,6 +771,24 @@ function algorithmOf(token) {
747
771
  throw new AuthioTokenValidationError("decryption_failed", "The encrypted token's header could not be read.", { cause: error });
748
772
  }
749
773
  }
774
+ function contentMethodOf(token) {
775
+ try {
776
+ return String(decodeProtectedHeader(token).enc ?? "");
777
+ } catch (error) {
778
+ throw new AuthioTokenValidationError("decryption_failed", "The encrypted token's header could not be read.", { cause: error });
779
+ }
780
+ }
781
+ function resolveAllowlist(configured, defaults, supported, setting) {
782
+ if (configured === void 0 || configured.length === 0) return defaults;
783
+ for (const value of configured) {
784
+ if (AuthioLegacyKeyManagementAlgorithms.includes(value))
785
+ throw new AuthioConfigurationError(
786
+ `${setting} cannot hold ${value}: Node and WebCrypto cannot decrypt PKCS#1 v1.5; register RSA-OAEP-256 as the client's encryption algorithm in Authio.`
787
+ );
788
+ if (!supported.includes(value)) throw new AuthioConfigurationError(`${setting} holds '${value}'; it accepts ${supported.join(", ")}.`);
789
+ }
790
+ return [...new Set(configured)];
791
+ }
750
792
  async function importDecryptionKey(key, algorithm, setting) {
751
793
  try {
752
794
  if (typeof key !== "string") return await importPrivateJwk(key, algorithm, setting);
@@ -803,7 +845,7 @@ async function verifyAuthioJwt(token, keys, expected) {
803
845
  try {
804
846
  const { payload, protectedHeader } = await jwtVerify(token, keys, {
805
847
  issuer: expected.issuer,
806
- audience: [...expected.audiences],
848
+ audience: expected.audiences ? [...expected.audiences] : void 0,
807
849
  algorithms: [...expected.algorithms && expected.algorithms.length > 0 ? expected.algorithms : AuthioAsymmetricAlgorithms],
808
850
  clockTolerance: expected.clockSkew ?? AuthioDefaults.ClockSkew,
809
851
  requiredClaims: [.../* @__PURE__ */ new Set(["exp", ...expected.requiredClaims ?? []])],
@@ -811,9 +853,34 @@ async function verifyAuthioJwt(token, keys, expected) {
811
853
  });
812
854
  return { payload, header: protectedHeader };
813
855
  } catch (error) {
814
- throw toTokenValidationError(error, expected.audiences, token);
856
+ if (error instanceof AuthioConfigurationError) throw error;
857
+ throw toTokenValidationError(error, expected.audiences ?? [], token);
815
858
  }
816
859
  }
860
+ function withClientSecret(keys, secret) {
861
+ if (!secret) return keys;
862
+ return async (header, token) => {
863
+ const algorithm = String(header.alg);
864
+ if (!AuthioHmacAlgorithms.includes(algorithm)) return keys(header, token);
865
+ const bytes = new TextEncoder().encode(await secret());
866
+ requireHmacSecretLength(algorithm, bytes.length);
867
+ return bytes;
868
+ };
869
+ }
870
+ function requireHmacSecretLength(algorithm, length) {
871
+ const minimum = AuthioHmacMinimumSecretBytes[algorithm];
872
+ if (minimum !== void 0 && length < minimum)
873
+ throw new AuthioConfigurationError(
874
+ `The Authio clientSecret has ${length} bytes, and ${algorithm} needs at least ${minimum} (RFC 7518 \xA73.2): Authio refuses a shorter secret for it.`
875
+ );
876
+ }
877
+ function acceptedSigningAlgorithms(configured, announced) {
878
+ if (configured) return [configured];
879
+ const asymmetric = (Array.isArray(announced) ? announced : []).filter(
880
+ (algorithm) => typeof algorithm === "string" && AuthioAsymmetricAlgorithms.includes(algorithm)
881
+ );
882
+ return asymmetric.length > 0 ? asymmetric : AuthioAsymmetricAlgorithms;
883
+ }
817
884
  function toTokenValidationError(error, audiences, token) {
818
885
  if (error instanceof AuthioTokenValidationError) return error;
819
886
  const refuse = (reason, message) => new AuthioTokenValidationError(reason, message, { cause: error });
@@ -945,6 +1012,7 @@ function toBase64Url(bytes) {
945
1012
  }
946
1013
 
947
1014
  // src/authorization.ts
1015
+ var AuthioChecks = ["pkce", "state", "nonce", "none"];
948
1016
  async function createAuthioPkce(method = "S256") {
949
1017
  if (method !== "S256" && method !== "plain") throw new TypeError(`The PKCE method '${String(method)}' is not S256 or plain.`);
950
1018
  const codeVerifier = randomValue(32);
@@ -954,14 +1022,26 @@ async function createAuthioPkce(method = "S256") {
954
1022
  function randomValue(bytes = 32) {
955
1023
  return toBase64Url2(crypto.getRandomValues(new Uint8Array(bytes)));
956
1024
  }
1025
+ function resolveChecks(checks, setting = "checks") {
1026
+ const resolved = [];
1027
+ for (const check of checks ?? []) {
1028
+ if (!AuthioChecks.includes(check))
1029
+ throw new AuthioConfigurationError(`The Authio ${setting} value '${String(check)}' is not one of ${AuthioChecks.join(", ")}.`);
1030
+ if (check !== "none" && !resolved.includes(check)) resolved.push(check);
1031
+ }
1032
+ return Object.freeze(resolved);
1033
+ }
957
1034
  async function buildAuthorizationUrl(endpoint, clientId, request) {
958
- const pkce = await createAuthioPkce(request.codeChallengeMethod ?? "S256");
959
- const state = request.state?.trim() || randomValue();
960
- const nonce = request.nonce?.trim() || randomValue();
1035
+ const checks = resolveChecks(request.checks);
1036
+ const pkce = checks.includes("pkce") ? await createAuthioPkce(request.codeChallengeMethod ?? "S256") : void 0;
1037
+ const state = checks.includes("state") ? request.state?.trim() || randomValue() : void 0;
1038
+ const nonce = checks.includes("nonce") ? request.nonce?.trim() || randomValue() : void 0;
961
1039
  if (request.maxAge !== void 0 && (!Number.isInteger(request.maxAge) || request.maxAge < 0))
962
1040
  throw new RangeError("maxAge must be a non-negative whole number of seconds.");
963
1041
  const display = request.popup ? "popup" : request.display;
964
1042
  const responseMode = request.popup ? "web_message" : request.responseMode;
1043
+ if (responseMode !== void 0 && responseMode !== "query" && responseMode !== "web_message")
1044
+ throw new AuthioConfigurationError(`The Authio responseMode '${String(responseMode)}' is not query or web_message.`);
965
1045
  const url = new URL(endpoint);
966
1046
  const parameters = {
967
1047
  ...request.extraParameters,
@@ -969,10 +1049,10 @@ async function buildAuthorizationUrl(endpoint, clientId, request) {
969
1049
  client_id: clientId,
970
1050
  redirect_uri: request.redirectUri,
971
1051
  scope: toScopeString(request.scopes) ?? "openid",
972
- state,
973
- nonce,
974
- code_challenge: pkce.codeChallenge,
975
- code_challenge_method: pkce.codeChallengeMethod,
1052
+ state: state ?? request.state?.trim(),
1053
+ nonce: nonce ?? request.nonce?.trim(),
1054
+ code_challenge: pkce?.codeChallenge,
1055
+ code_challenge_method: pkce?.codeChallengeMethod,
976
1056
  resource: request.resource,
977
1057
  organization: request.organization,
978
1058
  prompt: joined(request.prompt),
@@ -989,10 +1069,10 @@ async function buildAuthorizationUrl(endpoint, clientId, request) {
989
1069
  return {
990
1070
  url: url.toString(),
991
1071
  transaction: Object.freeze({
992
- state,
993
- nonce,
994
- codeVerifier: pkce.codeVerifier,
995
- codeChallengeMethod: pkce.codeChallengeMethod,
1072
+ checks,
1073
+ ...state ? { state } : {},
1074
+ ...nonce ? { nonce } : {},
1075
+ ...pkce ? { codeVerifier: pkce.codeVerifier, codeChallengeMethod: pkce.codeChallengeMethod } : {},
996
1076
  redirectUri: request.redirectUri,
997
1077
  ...request.resource ? { resource: request.resource } : {},
998
1078
  ...request.maxAge !== void 0 ? { maxAge: request.maxAge } : {}
@@ -1014,6 +1094,16 @@ function readCallbackParameters(callback) {
1014
1094
  }
1015
1095
  return parameters;
1016
1096
  }
1097
+ function readAuthioFrontChannelLogout(request, issuer) {
1098
+ const parameters = readCallbackParameters(request);
1099
+ const sessionId = parameters.sid?.trim() || void 0;
1100
+ const sentIssuer = parameters.iss?.trim() || void 0;
1101
+ if (sentIssuer !== void 0 && sentIssuer.replace(/\/+$/, "") !== issuer.replace(/\/+$/, ""))
1102
+ throw new AuthioCallbackError("issuer_mismatch", `The front-channel logout comes from the issuer '${sentIssuer}', not '${issuer}'.`);
1103
+ if (sessionId !== void 0 && sentIssuer === void 0)
1104
+ throw new AuthioCallbackError("missing_issuer", "The front-channel logout names a sid without its iss.");
1105
+ return Object.freeze({ sessionId, issuer: sentIssuer });
1106
+ }
1017
1107
  function parseAuthioBearerChallenge(header) {
1018
1108
  if (!header || !/^\s*bearer(\s|$)/i.test(header)) return void 0;
1019
1109
  const values = {};
@@ -1049,22 +1139,35 @@ function createAuthioClient(options) {
1049
1139
  const authenticator = createClientAuthenticator(options, connection);
1050
1140
  const refreshSkewMs = seconds(options.tokenRefreshSkew, AuthioDefaults.TokenRefreshSkew, "tokenRefreshSkew");
1051
1141
  const clockSkew = seconds(options.clockSkew, AuthioDefaults.ClockSkew, "clockSkew") / 1e3;
1052
- const decrypt = createAuthioTokenDecrypter(resolveEncryptionKey(options), {
1142
+ const encryptionKey = resolveEncryptionKey(options);
1143
+ const decrypt = createAuthioTokenDecrypter(encryptionKey, {
1053
1144
  setting: options.clientEncryptionKey === void 0 && options.clientEncryptionKeyPath ? "clientEncryptionKeyPath" : "clientEncryptionKey",
1054
- allowLegacyEncryptionAlgorithms: options.allowLegacyEncryptionAlgorithms
1145
+ allowLegacyEncryptionAlgorithms: options.allowLegacyEncryptionAlgorithms,
1146
+ encryptionAlgorithms: options.encryptionAlgorithms,
1147
+ encryptionMethods: options.encryptionMethods
1055
1148
  });
1149
+ const checks = resolveChecks(options.checks);
1150
+ const codeChallengeMethod = resolveCodeChallengeMethod(options.codeChallengeMethod);
1151
+ const responseMode = resolveResponseMode(options.responseMode);
1152
+ const idTokenAlgorithm = resolveSigningAlgorithm(options.idTokenSignedResponseAlg, "idTokenSignedResponseAlg", options.clientSecret);
1153
+ const userInfoAlgorithm = resolveSigningAlgorithm(options.userinfoSignedResponseAlg, "userinfoSignedResponseAlg", options.clientSecret) ?? idTokenAlgorithm;
1154
+ const accessTokenAlgorithm = resolveSigningAlgorithm(options.accessTokenSignedResponseAlg, "accessTokenSignedResponseAlg", options.clientSecret);
1155
+ const clientSecret = options.clientSecret === void 0 ? void 0 : () => readSecret(options.clientSecret);
1056
1156
  const signingKeys = createAuthioSigningKeys(connection, discovery);
1057
1157
  const tokens = createTokenClient(connection, discovery, authenticator);
1058
1158
  const clientCredentials = createClientCredentialsCache(connection, authenticator.clientId, tokens, refreshSkewMs);
1059
- const validationContext = async (signal) => ({
1060
- keys: await signingKeys(signal),
1061
- decrypt,
1062
- issuer: connection.issuer,
1063
- clientId: authenticator.clientId,
1064
- algorithms: options.validAlgorithms,
1065
- clockSkew,
1066
- now: connection.clock.now()
1067
- });
1159
+ const validationContext = async (signal) => {
1160
+ const document = await discovery.get(signal);
1161
+ return {
1162
+ keys: withClientSecret(await signingKeys(signal), clientSecret),
1163
+ decrypt,
1164
+ issuer: connection.issuer,
1165
+ clientId: authenticator.clientId,
1166
+ algorithms: acceptedSigningAlgorithms(idTokenAlgorithm, document.id_token_signing_alg_values_supported),
1167
+ clockSkew,
1168
+ now: connection.clock.now()
1169
+ };
1170
+ };
1068
1171
  const validateIdToken = async (idToken, expectations = {}) => {
1069
1172
  requireValue(idToken, "idToken");
1070
1173
  return validateAuthioIdToken(idToken, await validationContext(expectations.signal), expectations);
@@ -1073,7 +1176,13 @@ function createAuthioClient(options) {
1073
1176
  const redirectUri = request.redirectUri ?? options.redirectUri;
1074
1177
  requireValue(redirectUri, "redirectUri");
1075
1178
  const document = await discovery.get(request.signal);
1076
- return buildAuthorizationUrl(requireEndpoint(document, "authorization_endpoint"), authenticator.clientId, { ...request, redirectUri });
1179
+ return buildAuthorizationUrl(requireEndpoint(document, "authorization_endpoint"), authenticator.clientId, {
1180
+ ...request,
1181
+ redirectUri,
1182
+ checks: request.checks ?? checks,
1183
+ codeChallengeMethod: request.codeChallengeMethod ?? codeChallengeMethod,
1184
+ responseMode: request.responseMode ?? responseMode
1185
+ });
1077
1186
  };
1078
1187
  return {
1079
1188
  issuer: connection.issuer,
@@ -1117,12 +1226,19 @@ function createAuthioClient(options) {
1117
1226
  );
1118
1227
  const mediaType = response.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
1119
1228
  if (response.ok && mediaType === "application/jwt")
1120
- return readUserInfoJwt((await response.text()).trim(), document, connection, authenticator.clientId, decrypt, signingKeys, {
1121
- algorithms: options.validAlgorithms,
1122
- clockSkew,
1123
- status: response.status,
1124
- signal: callOptions.signal
1125
- });
1229
+ return readUserInfoJwt(
1230
+ (await response.text()).trim(),
1231
+ document,
1232
+ connection,
1233
+ authenticator.clientId,
1234
+ decrypt,
1235
+ withClientSecret(await signingKeys(callOptions.signal), clientSecret),
1236
+ {
1237
+ algorithms: acceptedSigningAlgorithms(userInfoAlgorithm, document.userinfo_signing_alg_values_supported ?? document.id_token_signing_alg_values_supported),
1238
+ clockSkew,
1239
+ status: response.status
1240
+ }
1241
+ );
1126
1242
  if (!response.ok) {
1127
1243
  const body = await response.text();
1128
1244
  const challenge = toErrorResponse(body) ? void 0 : readBearerChallenge(response);
@@ -1132,9 +1248,10 @@ function createAuthioClient(options) {
1132
1248
  },
1133
1249
  createAuthorizationUrl,
1134
1250
  async handleAuthorizationCallback(callback, transaction, callOptions = {}) {
1135
- if (!transaction?.state || !transaction.redirectUri) throw new TypeError("transaction is required: keep what createAuthorizationUrl returned.");
1251
+ if (!transaction?.redirectUri || !Array.isArray(transaction.checks))
1252
+ throw new TypeError("transaction is required: keep what createAuthorizationUrl returned.");
1136
1253
  const parameters = readCallbackParameters(callback);
1137
- if (parameters.state !== transaction.state)
1254
+ if (transaction.checks.includes("state") && (!transaction.state || parameters.state !== transaction.state))
1138
1255
  throw new AuthioCallbackError("state_mismatch", "The callback's state is not the one this sign-in was started with.");
1139
1256
  const document = await discovery.get(callOptions.signal);
1140
1257
  if (parameters.iss !== void 0) {
@@ -1148,12 +1265,12 @@ function createAuthioClient(options) {
1148
1265
  const answer = await tokens.authorizationCode({
1149
1266
  code: parameters.code,
1150
1267
  redirectUri: transaction.redirectUri,
1151
- codeVerifier: transaction.codeVerifier,
1268
+ codeVerifier: transaction.checks.includes("pkce") ? transaction.codeVerifier : void 0,
1152
1269
  resource: transaction.resource,
1153
1270
  signal: callOptions.signal
1154
1271
  });
1155
1272
  const idToken = answer.id_token ? await validateIdToken(answer.id_token, {
1156
- nonce: transaction.nonce,
1273
+ nonce: transaction.checks.includes("nonce") ? transaction.nonce : void 0,
1157
1274
  accessToken: answer.access_token,
1158
1275
  maxAge: transaction.maxAge,
1159
1276
  signal: callOptions.signal
@@ -1165,6 +1282,23 @@ function createAuthioClient(options) {
1165
1282
  requireValue(logoutToken, "logoutToken");
1166
1283
  return validateAuthioLogoutToken(logoutToken, await validationContext(callOptions.signal));
1167
1284
  },
1285
+ validateFrontChannelLogout(request) {
1286
+ return readAuthioFrontChannelLogout(request, connection.issuer);
1287
+ },
1288
+ async readAccessTokenClaims(accessToken, callOptions = {}) {
1289
+ requireValue(accessToken, "accessToken");
1290
+ if (isAuthioTokenEncrypted(accessToken) && encryptionKey === void 0) return void 0;
1291
+ const signed = await decrypt(accessToken);
1292
+ if (signed.split(".").length !== 3) return void 0;
1293
+ const document = await discovery.get(callOptions.signal);
1294
+ const { payload } = await verifyAuthioJwt(signed, withClientSecret(await signingKeys(callOptions.signal), clientSecret), {
1295
+ issuer: connection.issuer,
1296
+ algorithms: acceptedSigningAlgorithms(accessTokenAlgorithm, document.id_token_signing_alg_values_supported),
1297
+ clockSkew,
1298
+ now: connection.clock.now()
1299
+ });
1300
+ return payload;
1301
+ },
1168
1302
  async createEndSessionUrl(request = {}) {
1169
1303
  const document = await discovery.get(request.signal);
1170
1304
  const url = new URL(requireEndpoint(document, "end_session_endpoint"));
@@ -1256,7 +1390,7 @@ function createTokenClient(connection, discovery, authenticator) {
1256
1390
  refresh: (options) => {
1257
1391
  requireValue(options?.refreshToken, "refreshToken");
1258
1392
  return requestToken(
1259
- { grant_type: AuthioGrantTypes.RefreshToken, refresh_token: options.refreshToken, scope: toScopeString(options.scopes) },
1393
+ { grant_type: AuthioGrantTypes.RefreshToken, refresh_token: options.refreshToken, scope: toScopeString(options.scopes), resource: options.resource },
1260
1394
  options.signal
1261
1395
  );
1262
1396
  },
@@ -1451,10 +1585,10 @@ async function postForm(connection, discovery, authenticator, endpoint, paramete
1451
1585
  await authenticator?.apply(form, headers);
1452
1586
  return send(connection, url, { method: "POST", headers, body: form.toString() }, signal);
1453
1587
  }
1454
- async function readUserInfoJwt(jwt, document, connection, clientId, decrypt, signingKeys, settings) {
1588
+ async function readUserInfoJwt(jwt, document, connection, clientId, decrypt, keys, settings) {
1455
1589
  try {
1456
1590
  const signed = isAuthioTokenEncrypted(jwt) ? await decrypt(jwt) : jwt;
1457
- const { payload } = await verifyAuthioJwt(signed, await signingKeys(settings.signal), {
1591
+ const { payload } = await verifyAuthioJwt(signed, keys, {
1458
1592
  issuer: document.issuer.replace(/\/+$/, ""),
1459
1593
  audiences: [clientId],
1460
1594
  algorithms: settings.algorithms,
@@ -1486,6 +1620,33 @@ function readBearerChallenge(response) {
1486
1620
  }
1487
1621
  return error ? { error, description } : void 0;
1488
1622
  }
1623
+ function resolveCodeChallengeMethod(method) {
1624
+ if (method !== void 0 && method !== "S256" && method !== "plain")
1625
+ throw new AuthioConfigurationError(`The Authio codeChallengeMethod '${String(method)}' is not S256 or plain.`);
1626
+ return method;
1627
+ }
1628
+ function resolveResponseMode(mode) {
1629
+ if (mode !== void 0 && mode !== "query" && mode !== "web_message")
1630
+ throw new AuthioConfigurationError(`The Authio responseMode '${String(mode)}' is not query or web_message.`);
1631
+ return mode;
1632
+ }
1633
+ function resolveSigningAlgorithm(algorithm, setting, clientSecret) {
1634
+ if (algorithm === void 0 || algorithm === "") return void 0;
1635
+ const symmetric = AuthioHmacAlgorithms.includes(algorithm);
1636
+ if (!symmetric && !AuthioAsymmetricAlgorithms.includes(algorithm))
1637
+ throw new AuthioConfigurationError(
1638
+ `The Authio ${setting} '${algorithm}' is not one of ${[...AuthioAsymmetricAlgorithms, ...AuthioHmacAlgorithms].join(", ")}.`
1639
+ );
1640
+ if (symmetric && !clientSecret)
1641
+ throw new AuthioConfigurationError(`The Authio ${setting} ${algorithm} is verified with the client secret (OpenID Connect Core \xA710.1): set clientSecret.`);
1642
+ if (symmetric && typeof clientSecret === "string") requireHmacSecretLength(algorithm, new TextEncoder().encode(clientSecret).length);
1643
+ return algorithm;
1644
+ }
1645
+ async function readSecret(source) {
1646
+ const value = typeof source === "function" ? await source() : source;
1647
+ if (typeof value !== "string" || !value) throw new AuthioConfigurationError("The Authio clientSecret function returned no secret.");
1648
+ return value;
1649
+ }
1489
1650
  function requireValue(value, name) {
1490
1651
  if (typeof value !== "string" || !value.trim()) throw new TypeError(`${name} is required.`);
1491
1652
  }
@@ -1538,7 +1699,7 @@ function createAuthioAccountCredential(options) {
1538
1699
  realm: AuthioDefaults.PlatformRealm,
1539
1700
  clientId: kind === "client_secret" ? toCredentialClientId(options.credentialId) : AuthioDefaults.PlatformClientId,
1540
1701
  clientSecret: kind === "client_secret" ? value : void 0,
1541
- clientAuthentication: kind === "client_secret" ? "client_secret_post" : "none"
1702
+ tokenEndpointAuthMethod: kind === "client_secret" ? "client_secret_post" : "none"
1542
1703
  });
1543
1704
  }
1544
1705
  const exchange = async (signal) => {
@@ -1911,6 +2072,6 @@ function constantTimeEquals(left, right) {
1911
2072
  return difference === 0;
1912
2073
  }
1913
2074
 
1914
- export { AuthioAdminError, AuthioAsymmetricAlgorithms, AuthioCallbackError, AuthioCallerKinds, AuthioClaimTypes, AuthioClientAssertionAlgorithms, AuthioConfigurationError, AuthioContentEncryptionAlgorithms, AuthioDefaults, AuthioDiscoveryError, AuthioError, AuthioGrantTypes, AuthioKeyManagementAlgorithms, AuthioLegacyKeyManagementAlgorithms, AuthioOAuthErrors, AuthioPrompts, AuthioProtocolError, AuthioResourceAccess, AuthioResourceAccessClaims, AuthioScopes, AuthioTokenTypes, AuthioTokenValidationError, AuthioWebhookEventTypes, AuthioWebhookHeaders, asAdminResourceEvent, asAttackDetectedEvent, asCredentialCompromisedEvent, asKeysRotatedEvent, asLoginEvent, asPingEvent, asTokenReuseDetectedEvent, asTokenRevokedEvent, asUserEvent, asUserLockedOutEvent, asUserSuspensionEvent, computeAuthioTokenHash, computeWebhookSignatureHeader, createAuthioAccountCredential, createAuthioClient, createAuthioDiscoveryClient, createAuthioPkce, createAuthioSigningKeys, createAuthioTokenDecrypter, encryptionKeyFromFile, escapeDataString, isAllowedUrl, isAuthioTokenEncrypted, isKnownWebhookEventType, isWebhookEventOfType, parseAuthioAdminEnvelope, parseAuthioBearerChallenge, parseResourceAccess, parseResourceAccessClaim, parseWebhookEvent, randomValue, readAuthioAdminResponse, readWebhookEventData, resolveConnection, resolveIssuer, resourceAccessSourceOf, seconds, systemClock, toBasicAuthorization, toCamelCasedMembers, toClientCredentialsToken, toConnectionExchangeResult, toCredentialClientId, toDevicePollOutcome, toScopeString, toTokenValidationError, tryParseWebhookEvent, verifyAuthioJwt, verifyWebhookSignature };
2075
+ export { AuthioAdminError, AuthioAsymmetricAlgorithms, AuthioCallbackError, AuthioCallerKinds, AuthioChecks, AuthioClaimTypes, AuthioClientAssertionAlgorithms, AuthioConfigurationError, AuthioContentEncryptionAlgorithms, AuthioDefaults, AuthioDiscoveryError, AuthioError, AuthioGrantTypes, AuthioHmacAlgorithms, AuthioHmacMinimumSecretBytes, AuthioKeyManagementAlgorithms, AuthioLegacyKeyManagementAlgorithms, AuthioOAuthErrors, AuthioPrompts, AuthioProtocolError, AuthioResourceAccess, AuthioResourceAccessClaims, AuthioScopes, AuthioSupportedContentEncryptionAlgorithms, AuthioTokenEndpointAuthMethods, AuthioTokenTypes, AuthioTokenValidationError, AuthioWebhookEventTypes, AuthioWebhookHeaders, asAdminResourceEvent, asAttackDetectedEvent, asCredentialCompromisedEvent, asKeysRotatedEvent, asLoginEvent, asPingEvent, asTokenReuseDetectedEvent, asTokenRevokedEvent, asUserEvent, asUserLockedOutEvent, asUserSuspensionEvent, computeAuthioTokenHash, computeWebhookSignatureHeader, createAuthioAccountCredential, createAuthioClient, createAuthioDiscoveryClient, createAuthioPkce, createAuthioSigningKeys, createAuthioTokenDecrypter, encryptionKeyFromFile, escapeDataString, isAllowedUrl, isAuthioTokenEncrypted, isKnownWebhookEventType, isWebhookEventOfType, parseAuthioAdminEnvelope, parseAuthioBearerChallenge, parseResourceAccess, parseResourceAccessClaim, parseWebhookEvent, randomValue, readAuthioAdminResponse, readAuthioFrontChannelLogout, readWebhookEventData, requireHmacSecretLength, resolveConnection, resolveIssuer, resourceAccessSourceOf, seconds, systemClock, toBasicAuthorization, toCamelCasedMembers, toClientCredentialsToken, toConnectionExchangeResult, toCredentialClientId, toDevicePollOutcome, toScopeString, toTokenValidationError, tryParseWebhookEvent, verifyAuthioJwt, verifyWebhookSignature, withClientSecret };
1915
2076
  //# sourceMappingURL=index.js.map
1916
2077
  //# sourceMappingURL=index.js.map