authscape 1.0.766 → 1.0.768

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/index.js CHANGED
@@ -76,19 +76,30 @@ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
76
76
  function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
77
77
  function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; } // Re-export toast and transitions so pages can import from authscape
78
78
  // ============================================================================
79
- // Cookie utility function
79
+ // Auth Redirect Circuit Breaker
80
80
  // ============================================================================
81
- var setCookie = function setCookie(name, value) {
82
- var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
83
- return new Promise(function (resolve) {
84
- var cookieString = "".concat(name, "=").concat(value, ";");
85
- if (options.maxAge) cookieString += "max-age=".concat(options.maxAge, ";");
86
- if (options.path) cookieString += "path=".concat(options.path, ";");
87
- if (options.domain) cookieString += "domain=".concat(options.domain, ";");
88
- if (options.secure) cookieString += "secure;";
89
- document.cookie = cookieString;
90
- resolve();
91
- });
81
+ var AUTH_REDIRECT_KEY = 'authscape_redirect_count';
82
+ var AUTH_REDIRECT_TS_KEY = 'authscape_redirect_ts';
83
+ var AUTH_MAX_REDIRECTS = 3;
84
+ var AUTH_REDIRECT_WINDOW_MS = 30000; // 30 seconds
85
+
86
+ var checkAndIncrementRedirect = function checkAndIncrementRedirect() {
87
+ if (typeof window === 'undefined') return false;
88
+ var now = Date.now();
89
+ var storedTs = parseInt(sessionStorage.getItem(AUTH_REDIRECT_TS_KEY) || '0', 10);
90
+ var count = parseInt(sessionStorage.getItem(AUTH_REDIRECT_KEY) || '0', 10);
91
+ if (now - storedTs > AUTH_REDIRECT_WINDOW_MS) {
92
+ count = 0;
93
+ sessionStorage.setItem(AUTH_REDIRECT_TS_KEY, String(now));
94
+ }
95
+ count += 1;
96
+ sessionStorage.setItem(AUTH_REDIRECT_KEY, String(count));
97
+ return count <= AUTH_MAX_REDIRECTS;
98
+ };
99
+ var resetRedirectCounter = function resetRedirectCounter() {
100
+ if (typeof window === 'undefined') return;
101
+ sessionStorage.removeItem(AUTH_REDIRECT_KEY);
102
+ sessionStorage.removeItem(AUTH_REDIRECT_TS_KEY);
92
103
  };
93
104
 
94
105
  // ============================================================================
@@ -758,6 +769,7 @@ function AuthScapeApp(_ref10) {
758
769
  var queryCodeUsed = (0, _react.useRef)(null);
759
770
  var ga4React = (0, _react.useRef)(null);
760
771
  var errorTrackingInitializedRef = (0, _react.useRef)(false);
772
+ var loginRedirectPending = (0, _react.useRef)(false);
761
773
  var searchParams = (0, _navigation.useSearchParams)();
762
774
  var queryCode = (_searchParams$get = searchParams === null || searchParams === void 0 ? void 0 : searchParams.get("code")) !== null && _searchParams$get !== void 0 ? _searchParams$get : null;
763
775
  var pathname = (0, _navigation.usePathname)();
@@ -783,13 +795,14 @@ function AuthScapeApp(_ref10) {
783
795
  setIsSigningIn(true);
784
796
  codeVerifier = window.localStorage.getItem("verifier");
785
797
  if (!(!codeFromQuery || !codeVerifier)) {
786
- _context8.next = 11;
798
+ _context8.next = 12;
787
799
  break;
788
800
  }
789
801
  window.localStorage.clear();
790
- module.exports.authService().login();
802
+ setIsSigningIn(false);
803
+ setFrontEndLoadedState(true);
791
804
  return _context8.abrupt("return");
792
- case 11:
805
+ case 12:
793
806
  headers = {
794
807
  "Content-Type": "application/x-www-form-urlencoded"
795
808
  };
@@ -801,56 +814,51 @@ function AuthScapeApp(_ref10) {
801
814
  client_secret: process.env.client_secret,
802
815
  code_verifier: codeVerifier
803
816
  });
804
- _context8.prev = 13;
805
- _context8.next = 16;
817
+ _context8.prev = 14;
818
+ _context8.next = 17;
806
819
  return _axios["default"].post(process.env.authorityUri + "/connect/token", body, {
807
820
  headers: headers
808
821
  });
809
- case 16:
822
+ case 17:
810
823
  response = _context8.sent;
811
824
  domainHost = window.location.hostname.split(".").slice(-2).join(".");
812
825
  window.localStorage.removeItem("verifier");
813
- _context8.next = 21;
814
- return setCookie("access_token", response.data.access_token, {
815
- maxAge: 60 * 60 * 24 * 365,
826
+ _jsCookie["default"].set("access_token", response.data.access_token, {
827
+ expires: 365,
816
828
  path: "/",
817
829
  domain: domainHost,
818
830
  secure: true
819
831
  });
820
- case 21:
821
- _context8.next = 23;
822
- return setCookie("expires_in", response.data.expires_in, {
823
- maxAge: 60 * 60 * 24 * 365,
832
+ _jsCookie["default"].set("expires_in", String(response.data.expires_in), {
833
+ expires: 365,
824
834
  path: "/",
825
835
  domain: domainHost,
826
836
  secure: true
827
837
  });
828
- case 23:
829
- _context8.next = 25;
830
- return setCookie("refresh_token", response.data.refresh_token, {
831
- maxAge: 60 * 60 * 24 * 365,
838
+ _jsCookie["default"].set("refresh_token", response.data.refresh_token, {
839
+ expires: 365,
832
840
  path: "/",
833
841
  domain: domainHost,
834
842
  secure: true
835
843
  });
836
- case 25:
844
+ resetRedirectCounter();
837
845
  redirectUri = window.localStorage.getItem("redirectUri") || "/";
838
846
  window.localStorage.clear();
839
847
  window.location.href = redirectUri;
840
- _context8.next = 36;
848
+ _context8.next = 35;
841
849
  break;
842
- case 30:
843
- _context8.prev = 30;
844
- _context8.t0 = _context8["catch"](13);
850
+ case 29:
851
+ _context8.prev = 29;
852
+ _context8.t0 = _context8["catch"](14);
845
853
  console.error("PKCE sign-in failed", _context8.t0);
846
854
  window.localStorage.clear();
847
855
  setIsSigningIn(false);
848
- module.exports.authService().login();
849
- case 36:
856
+ setFrontEndLoadedState(true);
857
+ case 35:
850
858
  case "end":
851
859
  return _context8.stop();
852
860
  }
853
- }, _callee8, null, [[13, 30]]);
861
+ }, _callee8, null, [[14, 29]]);
854
862
  }));
855
863
  return function signInValidator(_x4) {
856
864
  return _ref11.apply(this, arguments);
@@ -961,7 +969,12 @@ function AuthScapeApp(_ref10) {
961
969
  };
962
970
  }, [frontEndLoadedState, pageProps.googleAnalytics4Code, pageProps.microsoftClarityCode]);
963
971
  (0, _react.useEffect)(function () {
964
- if (enforceLoggedIn && pathname !== "/signin-oidc" && frontEndLoadedState && !signedInUserState) {
972
+ if (enforceLoggedIn && pathname !== "/signin-oidc" && frontEndLoadedState && !signedInUserState && !loginRedirectPending.current) {
973
+ if (!checkAndIncrementRedirect()) {
974
+ console.warn('[AuthScape] Auth redirect loop detected — halting redirects.');
975
+ return;
976
+ }
977
+ loginRedirectPending.current = true;
965
978
  module.exports.authService().login();
966
979
  }
967
980
  }, [signedInUserState, enforceLoggedIn, frontEndLoadedState, pathname]);
@@ -9599,19 +9612,6 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
9599
9612
  function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return e; }; var t, e = {}, r = Object.prototype, n = r.hasOwnProperty, o = Object.defineProperty || function (t, e, r) { t[e] = r.value; }, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", c = i.asyncIterator || "@@asyncIterator", u = i.toStringTag || "@@toStringTag"; function define(t, e, r) { return Object.defineProperty(t, e, { value: r, enumerable: !0, configurable: !0, writable: !0 }), t[e]; } try { define({}, ""); } catch (t) { define = function define(t, e, r) { return t[e] = r; }; } function wrap(t, e, r, n) { var i = e && e.prototype instanceof Generator ? e : Generator, a = Object.create(i.prototype), c = new Context(n || []); return o(a, "_invoke", { value: makeInvokeMethod(t, r, c) }), a; } function tryCatch(t, e, r) { try { return { type: "normal", arg: t.call(e, r) }; } catch (t) { return { type: "throw", arg: t }; } } e.wrap = wrap; var h = "suspendedStart", l = "suspendedYield", f = "executing", s = "completed", y = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var p = {}; define(p, a, function () { return this; }); var d = Object.getPrototypeOf, v = d && d(d(values([]))); v && v !== r && n.call(v, a) && (p = v); var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p); function defineIteratorMethods(t) { ["next", "throw", "return"].forEach(function (e) { define(t, e, function (t) { return this._invoke(e, t); }); }); } function AsyncIterator(t, e) { function invoke(r, o, i, a) { var c = tryCatch(t[r], t, o); if ("throw" !== c.type) { var u = c.arg, h = u.value; return h && "object" == _typeof(h) && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) { invoke("next", t, i, a); }, function (t) { invoke("throw", t, i, a); }) : e.resolve(h).then(function (t) { u.value = t, i(u); }, function (t) { return invoke("throw", t, i, a); }); } a(c.arg); } var r; o(this, "_invoke", { value: function value(t, n) { function callInvokeWithMethodAndArg() { return new e(function (e, r) { invoke(t, n, e, r); }); } return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(e, r, n) { var o = h; return function (i, a) { if (o === f) throw Error("Generator is already running"); if (o === s) { if ("throw" === i) throw a; return { value: t, done: !0 }; } for (n.method = i, n.arg = a;;) { var c = n.delegate; if (c) { var u = maybeInvokeDelegate(c, n); if (u) { if (u === y) continue; return u; } } if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) { if (o === h) throw o = s, n.arg; n.dispatchException(n.arg); } else "return" === n.method && n.abrupt("return", n.arg); o = f; var p = tryCatch(e, r, n); if ("normal" === p.type) { if (o = n.done ? s : l, p.arg === y) continue; return { value: p.arg, done: n.done }; } "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg); } }; } function maybeInvokeDelegate(e, r) { var n = r.method, o = e.iterator[n]; if (o === t) return r.delegate = null, "throw" === n && e.iterator["return"] && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y; var i = tryCatch(o, e.iterator, r.arg); if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y; var a = i.arg; return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y); } function pushTryEntry(t) { var e = { tryLoc: t[0] }; 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e); } function resetTryEntry(t) { var e = t.completion || {}; e.type = "normal", delete e.arg, t.completion = e; } function Context(t) { this.tryEntries = [{ tryLoc: "root" }], t.forEach(pushTryEntry, this), this.reset(!0); } function values(e) { if (e || "" === e) { var r = e[a]; if (r) return r.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var o = -1, i = function next() { for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next; return next.value = t, next.done = !0, next; }; return i.next = i; } } throw new TypeError(_typeof(e) + " is not iterable"); } return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), o(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) { var e = "function" == typeof t && t.constructor; return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name)); }, e.mark = function (t) { return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t; }, e.awrap = function (t) { return { __await: t }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () { return this; }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) { void 0 === i && (i = Promise); var a = new AsyncIterator(wrap(t, r, n, o), i); return e.isGeneratorFunction(r) ? a : a.next().then(function (t) { return t.done ? t.value : a.next(); }); }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () { return this; }), define(g, "toString", function () { return "[object Generator]"; }), e.keys = function (t) { var e = Object(t), r = []; for (var n in e) r.push(n); return r.reverse(), function next() { for (; r.length;) { var t = r.pop(); if (t in e) return next.value = t, next.done = !1, next; } return next.done = !0, next; }; }, e.values = values, Context.prototype = { constructor: Context, reset: function reset(e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t); }, stop: function stop() { this.done = !0; var t = this.tryEntries[0].completion; if ("throw" === t.type) throw t.arg; return this.rval; }, dispatchException: function dispatchException(e) { if (this.done) throw e; var r = this; function handle(n, o) { return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o; } for (var o = this.tryEntries.length - 1; o >= 0; --o) { var i = this.tryEntries[o], a = i.completion; if ("root" === i.tryLoc) return handle("end"); if (i.tryLoc <= this.prev) { var c = n.call(i, "catchLoc"), u = n.call(i, "finallyLoc"); if (c && u) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } else if (c) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); } else { if (!u) throw Error("try statement without catch or finally"); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } } } }, abrupt: function abrupt(t, e) { for (var r = this.tryEntries.length - 1; r >= 0; --r) { var o = this.tryEntries[r]; if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) { var i = o; break; } } i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null); var a = i ? i.completion : {}; return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a); }, complete: function complete(t, e) { if ("throw" === t.type) throw t.arg; return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y; }, finish: function finish(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y; } }, "catch": function _catch(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.tryLoc === t) { var n = r.completion; if ("throw" === n.type) { var o = n.arg; resetTryEntry(r); } return o; } } throw Error("illegal catch attempt"); }, delegateYield: function delegateYield(e, r, n) { return this.delegate = { iterator: values(e), resultName: r, nextLoc: n }, "next" === this.method && (this.arg = t), y; } }, e; }
9600
9613
  function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
9601
9614
  function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
9602
- // Cookie utility function
9603
- var setCookie = function setCookie(name, value) {
9604
- var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
9605
- return new Promise(function (resolve) {
9606
- var cookieString = "".concat(name, "=").concat(value, ";");
9607
- if (options.maxAge) cookieString += "max-age=".concat(options.maxAge, ";");
9608
- if (options.path) cookieString += "path=".concat(options.path, ";");
9609
- if (options.domain) cookieString += "domain=".concat(options.domain, ";");
9610
- if (options.secure) cookieString += "secure;";
9611
- document.cookie = cookieString;
9612
- resolve();
9613
- });
9614
- };
9615
9615
  var setupDefaultOptions = /*#__PURE__*/function () {
9616
9616
  var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
9617
9617
  var ctx,
@@ -9658,9 +9658,16 @@ var RefreshToken = /*#__PURE__*/function () {
9658
9658
  return _regeneratorRuntime().wrap(function _callee2$(_context2) {
9659
9659
  while (1) switch (_context2.prev = _context2.next) {
9660
9660
  case 0:
9661
+ _context2.prev = 0;
9661
9662
  accessToken = _jsCookie["default"].get('access_token') || '';
9662
9663
  refreshToken = _jsCookie["default"].get('refresh_token') || '';
9663
- _context2.next = 4;
9664
+ if (refreshToken) {
9665
+ _context2.next = 5;
9666
+ break;
9667
+ }
9668
+ return _context2.abrupt("return", false);
9669
+ case 5:
9670
+ _context2.next = 7;
9664
9671
  return instance.post(process.env.authorityUri + "/connect/token", _queryString["default"].stringify({
9665
9672
  grant_type: 'refresh_token',
9666
9673
  client_id: process.env.client_id,
@@ -9672,42 +9679,44 @@ var RefreshToken = /*#__PURE__*/function () {
9672
9679
  "Authorization": "Bearer " + accessToken
9673
9680
  }
9674
9681
  });
9675
- case 4:
9682
+ case 7:
9676
9683
  response = _context2.sent;
9677
9684
  if (!(response != null && response.status == 200)) {
9678
- _context2.next = 14;
9685
+ _context2.next = 15;
9679
9686
  break;
9680
9687
  }
9681
9688
  domainHost = window.location.hostname.split('.').slice(-2).join('.');
9682
9689
  originalRequest.headers['Authorization'] = 'Bearer ' + response.data.access_token;
9683
- _context2.next = 10;
9684
- return setCookie('access_token', response.data.access_token, {
9685
- maxAge: 60 * 60 * 24 * 365,
9690
+ _jsCookie["default"].set('access_token', response.data.access_token, {
9691
+ expires: 365,
9686
9692
  path: '/',
9687
9693
  domain: domainHost,
9688
9694
  secure: true
9689
9695
  });
9690
- case 10:
9691
- _context2.next = 12;
9692
- return setCookie('expires_in', response.data.expires_in, {
9693
- maxAge: 60 * 60 * 24 * 365,
9696
+ _jsCookie["default"].set('expires_in', String(response.data.expires_in), {
9697
+ expires: 365,
9694
9698
  path: '/',
9695
9699
  domain: domainHost,
9696
9700
  secure: true
9697
9701
  });
9698
- case 12:
9699
- _context2.next = 14;
9700
- return setCookie('refresh_token', response.data.refresh_token, {
9701
- maxAge: 60 * 60 * 24 * 365,
9702
+ _jsCookie["default"].set('refresh_token', response.data.refresh_token, {
9703
+ expires: 365,
9702
9704
  path: '/',
9703
9705
  domain: domainHost,
9704
9706
  secure: true
9705
9707
  });
9706
- case 14:
9708
+ return _context2.abrupt("return", true);
9709
+ case 15:
9710
+ return _context2.abrupt("return", false);
9711
+ case 18:
9712
+ _context2.prev = 18;
9713
+ _context2.t0 = _context2["catch"](0);
9714
+ return _context2.abrupt("return", false);
9715
+ case 21:
9707
9716
  case "end":
9708
9717
  return _context2.stop();
9709
9718
  }
9710
- }, _callee2);
9719
+ }, _callee2, null, [[0, 18]]);
9711
9720
  }));
9712
9721
  return function RefreshToken(_x, _x2) {
9713
9722
  return _ref2.apply(this, arguments);
@@ -9728,48 +9737,58 @@ var apiService = exports.apiService = function apiService() {
9728
9737
  return response;
9729
9738
  }, /*#__PURE__*/function () {
9730
9739
  var _ref3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee3(error) {
9731
- var originalConfig, domainHost;
9740
+ var originalConfig, refreshed, domainHost;
9732
9741
  return _regeneratorRuntime().wrap(function _callee3$(_context3) {
9733
9742
  while (1) switch (_context3.prev = _context3.next) {
9734
9743
  case 0:
9735
9744
  originalConfig = error.config;
9736
9745
  if (!error.response) {
9737
- _context3.next = 10;
9746
+ _context3.next = 13;
9738
9747
  break;
9739
9748
  }
9740
9749
  if (!(error.response.status === 401 && !originalConfig._retry)) {
9741
- _context3.next = 7;
9750
+ _context3.next = 10;
9742
9751
  break;
9743
9752
  }
9744
9753
  originalConfig._retry = true;
9745
9754
  _context3.next = 6;
9746
9755
  return RefreshToken(originalConfig, instance);
9747
9756
  case 6:
9757
+ refreshed = _context3.sent;
9758
+ if (!refreshed) {
9759
+ _context3.next = 9;
9760
+ break;
9761
+ }
9748
9762
  return _context3.abrupt("return", instance.request(originalConfig));
9749
- case 7:
9763
+ case 9:
9764
+ return _context3.abrupt("return", Promise.reject(error));
9765
+ case 10:
9750
9766
  if (!(error.response.status === 400)) {
9751
- _context3.next = 10;
9767
+ _context3.next = 13;
9752
9768
  break;
9753
9769
  }
9754
9770
  if (error.response.config.url.includes("/connect/token")) {
9755
9771
  domainHost = window.location.hostname.split('.').slice(-2).join('.');
9756
9772
  _jsCookie["default"].remove('access_token', {
9757
9773
  path: '/',
9758
- domain: domainHost
9774
+ domain: domainHost,
9775
+ secure: true
9759
9776
  });
9760
9777
  _jsCookie["default"].remove('refresh_token', {
9761
9778
  path: '/',
9762
- domain: domainHost
9779
+ domain: domainHost,
9780
+ secure: true
9763
9781
  });
9764
9782
  _jsCookie["default"].remove('expires_in', {
9765
9783
  path: '/',
9766
- domain: domainHost
9784
+ domain: domainHost,
9785
+ secure: true
9767
9786
  });
9768
9787
  }
9769
9788
  return _context3.abrupt("return", Promise.reject(error));
9770
- case 10:
9789
+ case 13:
9771
9790
  return _context3.abrupt("return", Promise.reject(error));
9772
- case 11:
9791
+ case 14:
9773
9792
  case "end":
9774
9793
  return _context3.stop();
9775
9794
  }
@@ -10318,15 +10337,18 @@ var _authService = exports.authService = function authService() {
10318
10337
  AuthUri = process.env.authorityUri;
10319
10338
  _jsCookie["default"].remove('access_token', {
10320
10339
  path: '/',
10321
- domain: domainHost
10340
+ domain: domainHost,
10341
+ secure: true
10322
10342
  });
10323
10343
  _jsCookie["default"].remove('refresh_token', {
10324
10344
  path: '/',
10325
- domain: domainHost
10345
+ domain: domainHost,
10346
+ secure: true
10326
10347
  });
10327
10348
  _jsCookie["default"].remove('expires_in', {
10328
10349
  path: '/',
10329
- domain: domainHost
10350
+ domain: domainHost,
10351
+ secure: true
10330
10352
  });
10331
10353
 
10332
10354
  // destroyCookie({}, "access_token", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "authscape",
3
- "version": "1.0.766",
3
+ "version": "1.0.768",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -17,18 +17,33 @@ import { HubConnectionBuilder, LogLevel, HttpTransportType } from '@microsoft/si
17
17
  import Cookies from 'js-cookie';
18
18
 
19
19
  // ============================================================================
20
- // Cookie utility function
20
+ // Auth Redirect Circuit Breaker
21
21
  // ============================================================================
22
- const setCookie = (name, value, options = {}) => {
23
- return new Promise((resolve) => {
24
- let cookieString = `${name}=${value};`;
25
- if (options.maxAge) cookieString += `max-age=${options.maxAge};`;
26
- if (options.path) cookieString += `path=${options.path};`;
27
- if (options.domain) cookieString += `domain=${options.domain};`;
28
- if (options.secure) cookieString += `secure;`;
29
- document.cookie = cookieString;
30
- resolve();
31
- });
22
+ const AUTH_REDIRECT_KEY = 'authscape_redirect_count';
23
+ const AUTH_REDIRECT_TS_KEY = 'authscape_redirect_ts';
24
+ const AUTH_MAX_REDIRECTS = 3;
25
+ const AUTH_REDIRECT_WINDOW_MS = 30000; // 30 seconds
26
+
27
+ const checkAndIncrementRedirect = () => {
28
+ if (typeof window === 'undefined') return false;
29
+ const now = Date.now();
30
+ const storedTs = parseInt(sessionStorage.getItem(AUTH_REDIRECT_TS_KEY) || '0', 10);
31
+ let count = parseInt(sessionStorage.getItem(AUTH_REDIRECT_KEY) || '0', 10);
32
+
33
+ if (now - storedTs > AUTH_REDIRECT_WINDOW_MS) {
34
+ count = 0;
35
+ sessionStorage.setItem(AUTH_REDIRECT_TS_KEY, String(now));
36
+ }
37
+
38
+ count += 1;
39
+ sessionStorage.setItem(AUTH_REDIRECT_KEY, String(count));
40
+ return count <= AUTH_MAX_REDIRECTS;
41
+ };
42
+
43
+ const resetRedirectCounter = () => {
44
+ if (typeof window === 'undefined') return;
45
+ sessionStorage.removeItem(AUTH_REDIRECT_KEY);
46
+ sessionStorage.removeItem(AUTH_REDIRECT_TS_KEY);
32
47
  };
33
48
 
34
49
  // ============================================================================
@@ -484,6 +499,7 @@ export function AuthScapeApp({
484
499
  const queryCodeUsed = useRef(null);
485
500
  const ga4React = useRef(null);
486
501
  const errorTrackingInitializedRef = useRef(false);
502
+ const loginRedirectPending = useRef(false);
487
503
 
488
504
  const searchParams = useSearchParams();
489
505
  const queryCode = searchParams?.get("code") ?? null;
@@ -500,7 +516,8 @@ export function AuthScapeApp({
500
516
  const codeVerifier = window.localStorage.getItem("verifier");
501
517
  if (!codeFromQuery || !codeVerifier) {
502
518
  window.localStorage.clear();
503
- module.exports.authService().login();
519
+ setIsSigningIn(false);
520
+ setFrontEndLoadedState(true);
504
521
  return;
505
522
  }
506
523
 
@@ -526,25 +543,27 @@ export function AuthScapeApp({
526
543
 
527
544
  window.localStorage.removeItem("verifier");
528
545
 
529
- await setCookie("access_token", response.data.access_token, {
530
- maxAge: 60 * 60 * 24 * 365,
546
+ Cookies.set("access_token", response.data.access_token, {
547
+ expires: 365,
531
548
  path: "/",
532
549
  domain: domainHost,
533
550
  secure: true,
534
551
  });
535
- await setCookie("expires_in", response.data.expires_in, {
536
- maxAge: 60 * 60 * 24 * 365,
552
+ Cookies.set("expires_in", String(response.data.expires_in), {
553
+ expires: 365,
537
554
  path: "/",
538
555
  domain: domainHost,
539
556
  secure: true,
540
557
  });
541
- await setCookie("refresh_token", response.data.refresh_token, {
542
- maxAge: 60 * 60 * 24 * 365,
558
+ Cookies.set("refresh_token", response.data.refresh_token, {
559
+ expires: 365,
543
560
  path: "/",
544
561
  domain: domainHost,
545
562
  secure: true,
546
563
  });
547
564
 
565
+ resetRedirectCounter();
566
+
548
567
  const redirectUri = window.localStorage.getItem("redirectUri") || "/";
549
568
  window.localStorage.clear();
550
569
 
@@ -553,7 +572,7 @@ export function AuthScapeApp({
553
572
  console.error("PKCE sign-in failed", exp);
554
573
  window.localStorage.clear();
555
574
  setIsSigningIn(false);
556
- module.exports.authService().login();
575
+ setFrontEndLoadedState(true);
557
576
  }
558
577
  };
559
578
 
@@ -653,8 +672,14 @@ export function AuthScapeApp({
653
672
  enforceLoggedIn &&
654
673
  pathname !== "/signin-oidc" &&
655
674
  frontEndLoadedState &&
656
- !signedInUserState
675
+ !signedInUserState &&
676
+ !loginRedirectPending.current
657
677
  ) {
678
+ if (!checkAndIncrementRedirect()) {
679
+ console.warn('[AuthScape] Auth redirect loop detected — halting redirects.');
680
+ return;
681
+ }
682
+ loginRedirectPending.current = true;
658
683
  module.exports.authService().login();
659
684
  }
660
685
  }, [signedInUserState, enforceLoggedIn, frontEndLoadedState, pathname]);
@@ -3,19 +3,6 @@ import querystring from 'query-string';
3
3
  import fileDownload from 'js-file-download';
4
4
  import Cookies from 'js-cookie';
5
5
 
6
- // Cookie utility function
7
- const setCookie = (name, value, options = {}) => {
8
- return new Promise((resolve) => {
9
- let cookieString = `${name}=${value};`;
10
- if (options.maxAge) cookieString += `max-age=${options.maxAge};`;
11
- if (options.path) cookieString += `path=${options.path};`;
12
- if (options.domain) cookieString += `domain=${options.domain};`;
13
- if (options.secure) cookieString += `secure;`;
14
- document.cookie = cookieString;
15
- resolve();
16
- });
17
- };
18
-
19
6
  const setupDefaultOptions = async (ctx = null) => {
20
7
  let defaultOptions = {};
21
8
  if (ctx == null) {
@@ -42,46 +29,58 @@ const setupDefaultOptions = async (ctx = null) => {
42
29
  }
43
30
 
44
31
  const RefreshToken = async (originalRequest, instance) => {
45
- let accessToken = Cookies.get('access_token') || '';
46
- let refreshToken = Cookies.get('refresh_token') || '';
47
-
48
- let response = await instance.post(process.env.authorityUri + "/connect/token",
49
- querystring.stringify({
50
- grant_type: 'refresh_token',
51
- client_id: process.env.client_id,
52
- client_secret: process.env.client_secret,
53
- refresh_token: refreshToken
54
- }), {
55
- headers: {
56
- "Content-Type": "application/x-www-form-urlencoded",
57
- "Authorization": "Bearer " + accessToken
58
- }
59
- });
32
+ try {
33
+ let accessToken = Cookies.get('access_token') || '';
34
+ let refreshToken = Cookies.get('refresh_token') || '';
60
35
 
61
- if (response != null && response.status == 200) {
62
- let domainHost = window.location.hostname.split('.').slice(-2).join('.');
63
- originalRequest.headers['Authorization'] = 'Bearer ' + response.data.access_token;
36
+ if (!refreshToken) {
37
+ return false;
38
+ }
64
39
 
65
- await setCookie('access_token', response.data.access_token, {
66
- maxAge: 60 * 60 * 24 * 365,
67
- path: '/',
68
- domain: domainHost,
69
- secure: true
40
+ let response = await instance.post(process.env.authorityUri + "/connect/token",
41
+ querystring.stringify({
42
+ grant_type: 'refresh_token',
43
+ client_id: process.env.client_id,
44
+ client_secret: process.env.client_secret,
45
+ refresh_token: refreshToken
46
+ }), {
47
+ headers: {
48
+ "Content-Type": "application/x-www-form-urlencoded",
49
+ "Authorization": "Bearer " + accessToken
50
+ }
70
51
  });
71
52
 
72
- await setCookie('expires_in', response.data.expires_in, {
73
- maxAge: 60 * 60 * 24 * 365,
74
- path: '/',
75
- domain: domainHost,
76
- secure: true
77
- });
53
+ if (response != null && response.status == 200) {
54
+ let domainHost = window.location.hostname.split('.').slice(-2).join('.');
55
+ originalRequest.headers['Authorization'] = 'Bearer ' + response.data.access_token;
56
+
57
+ Cookies.set('access_token', response.data.access_token, {
58
+ expires: 365,
59
+ path: '/',
60
+ domain: domainHost,
61
+ secure: true
62
+ });
63
+
64
+ Cookies.set('expires_in', String(response.data.expires_in), {
65
+ expires: 365,
66
+ path: '/',
67
+ domain: domainHost,
68
+ secure: true
69
+ });
70
+
71
+ Cookies.set('refresh_token', response.data.refresh_token, {
72
+ expires: 365,
73
+ path: '/',
74
+ domain: domainHost,
75
+ secure: true
76
+ });
77
+
78
+ return true;
79
+ }
78
80
 
79
- await setCookie('refresh_token', response.data.refresh_token, {
80
- maxAge: 60 * 60 * 24 * 365,
81
- path: '/',
82
- domain: domainHost,
83
- secure: true
84
- });
81
+ return false;
82
+ } catch (err) {
83
+ return false;
85
84
  }
86
85
  }
87
86
 
@@ -107,16 +106,19 @@ export const apiService = (ctx = null) => {
107
106
  if (error.response) {
108
107
  if (error.response.status === 401 && !originalConfig._retry) {
109
108
  originalConfig._retry = true;
110
- await RefreshToken(originalConfig, instance);
111
- return instance.request(originalConfig);
109
+ const refreshed = await RefreshToken(originalConfig, instance);
110
+ if (refreshed) {
111
+ return instance.request(originalConfig);
112
+ }
113
+ return Promise.reject(error);
112
114
  }
113
115
 
114
116
  if (error.response.status === 400) {
115
117
  if (error.response.config.url.includes("/connect/token")) {
116
118
  let domainHost = window.location.hostname.split('.').slice(-2).join('.');
117
- Cookies.remove('access_token', { path: '/', domain: domainHost });
118
- Cookies.remove('refresh_token', { path: '/', domain: domainHost });
119
- Cookies.remove('expires_in', { path: '/', domain: domainHost });
119
+ Cookies.remove('access_token', { path: '/', domain: domainHost, secure: true });
120
+ Cookies.remove('refresh_token', { path: '/', domain: domainHost, secure: true });
121
+ Cookies.remove('expires_in', { path: '/', domain: domainHost, secure: true });
120
122
  }
121
123
  return Promise.reject(error);
122
124
  }
@@ -127,9 +127,9 @@ export const authService = () => {
127
127
  let AuthUri = process.env.authorityUri;
128
128
 
129
129
 
130
- Cookies.remove('access_token', { path: '/', domain: domainHost });
131
- Cookies.remove('refresh_token', { path: '/', domain: domainHost });
132
- Cookies.remove('expires_in', { path: '/', domain: domainHost });
130
+ Cookies.remove('access_token', { path: '/', domain: domainHost, secure: true });
131
+ Cookies.remove('refresh_token', { path: '/', domain: domainHost, secure: true });
132
+ Cookies.remove('expires_in', { path: '/', domain: domainHost, secure: true });
133
133
 
134
134
 
135
135
  // destroyCookie({}, "access_token", {