MCPcopy Create free account
hub / github.com/EvoMap/evolver / reAuthenticate

Method reAuthenticate

src/proxy/lifecycle/manager.js:934–1036  ·  view source on GitHub ↗

* Re-authenticate after 403: rotate secret via hello, then verify with a * heartbeat. Returns true if auth is restored, false otherwise. * * Recovery sequence (issue EvoMap/evolver#529): * attempt 1 -> hello with current Bearer + rotate_secret=true * (works when the s

()

Source from the content-addressed store, hash-verified

932 * manual-reset hint to the user instead of churning forever.
933 */
934 async reAuthenticate() {
935 if (this._reauthInProgress) return false;
936 if (this._reauthBackoffUntil > Date.now()) {
937 const waitSec = Math.ceil((this._reauthBackoffUntil - Date.now()) / 1000);
938 this.logger.warn(`[lifecycle] re-auth suppressed: backoff active for ${waitSec}s`);
939 return false;
940 }
941 this._reauthInProgress = true;
942 let manualResetRequired = false;
943 let hubUnreachable = false;
944 let droppedDivergedSecret = false;
945 try {
946 for (let attempt = 1; attempt <= MAX_REAUTH_ATTEMPTS; attempt++) {
947 this.logger.warn(`[lifecycle] re-auth attempt ${attempt}/${MAX_REAUTH_ATTEMPTS}: rotating secret via hello...`);
948 const helloResult = await this.hello({ rotateSecret: true });
949 if (!helloResult.ok) {
950 this.logger.error(`[lifecycle] re-auth hello failed: ${helloResult.error}`);
951 if (helloResult.error === 'hello_rate_limited' || helloResult.error === 'hello_rate_limit_active') break;
952 // Hub link is down (WAF HTML, network error, timeout) -- NOT an auth
953 // failure. Bail without arming the re-auth backoff: otherwise a
954 // transient outage that arrives mid-rotate would burn both attempts
955 // (attempt 2's hello short-circuits on the hub-unreachable window)
956 // and suppress genuine auth recovery for up to REAUTH_BACKOFF_MAX_MS,
957 // even though a JSON 401/403 retry would succeed once the hub is
958 // reachable again. The hub-unreachable window already gates re-entry.
959 if (helloResult.error === 'hub_unreachable' || helloResult.error === 'hub_unreachable_backoff') {
960 hubUnreachable = true;
961 break;
962 }
963 if (isSecretDivergenceError(helloResult.error)) {
964 // The hub has explicitly rejected our current secret as diverged
965 // from its record. Drop store/env-derived auth once, then spend
966 // the second attempt on an unauthenticated rotate hello instead
967 // of backing off while still presenting the same stale Bearer.
968 if (attempt < MAX_REAUTH_ATTEMPTS && !droppedDivergedSecret) {
969 this._dropLocalSecret(SECRET_DIVERGENCE_ERROR);
970 droppedDivergedSecret = true;
971 continue;
972 }
973 break;
974 }
975 if (typeof helloResult.error === 'string' && helloResult.error.startsWith('node_id_already_claimed')) {
976 // Hub does not believe we own this nodeId. Our locally cached
977 // secret(s) are useless. Drop them so attempt 2 retries WITHOUT
978 // a Bearer (lenient hello path). If even unauthenticated rotate
979 // is rejected, only a manual reset can recover.
980 if (attempt < MAX_REAUTH_ATTEMPTS) {
981 this._dropLocalSecret('node_id_already_claimed');
982 continue;
983 }
984 manualResetRequired = true;
985 break;
986 }
987 continue;
988 }
989 const newSecret = helloResult.response?.payload?.node_secret;
990 if (!newSecret) {
991 this.logger.error('[lifecycle] re-auth: hub did not return a new secret (rotate may not have taken effect)');

Calls 5

helloMethod · 0.95
_dropLocalSecretMethod · 0.95
heartbeatMethod · 0.95
isSecretDivergenceErrorFunction · 0.85

Tested by

no test coverage detected