authscape 1.0.764 → 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
  // ============================================================================
@@ -715,6 +726,7 @@ function ensureUserHelpers(u) {
715
726
  // AuthScapeApp Component
716
727
  // ============================================================================
717
728
  function AuthScapeApp(_ref10) {
729
+ var _searchParams$get;
718
730
  var Component = _ref10.Component,
719
731
  layout = _ref10.layout,
720
732
  loadingLayout = _ref10.loadingLayout,
@@ -757,8 +769,9 @@ function AuthScapeApp(_ref10) {
757
769
  var queryCodeUsed = (0, _react.useRef)(null);
758
770
  var ga4React = (0, _react.useRef)(null);
759
771
  var errorTrackingInitializedRef = (0, _react.useRef)(false);
772
+ var loginRedirectPending = (0, _react.useRef)(false);
760
773
  var searchParams = (0, _navigation.useSearchParams)();
761
- var queryCode = searchParams.get("code");
774
+ var queryCode = (_searchParams$get = searchParams === null || searchParams === void 0 ? void 0 : searchParams.get("code")) !== null && _searchParams$get !== void 0 ? _searchParams$get : null;
762
775
  var pathname = (0, _navigation.usePathname)();
763
776
  var signInValidator = /*#__PURE__*/function () {
764
777
  var _ref11 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee8(codeFromQuery) {
@@ -782,13 +795,14 @@ function AuthScapeApp(_ref10) {
782
795
  setIsSigningIn(true);
783
796
  codeVerifier = window.localStorage.getItem("verifier");
784
797
  if (!(!codeFromQuery || !codeVerifier)) {
785
- _context8.next = 11;
798
+ _context8.next = 12;
786
799
  break;
787
800
  }
788
801
  window.localStorage.clear();
789
- module.exports.authService().login();
802
+ setIsSigningIn(false);
803
+ setFrontEndLoadedState(true);
790
804
  return _context8.abrupt("return");
791
- case 11:
805
+ case 12:
792
806
  headers = {
793
807
  "Content-Type": "application/x-www-form-urlencoded"
794
808
  };
@@ -800,56 +814,51 @@ function AuthScapeApp(_ref10) {
800
814
  client_secret: process.env.client_secret,
801
815
  code_verifier: codeVerifier
802
816
  });
803
- _context8.prev = 13;
804
- _context8.next = 16;
817
+ _context8.prev = 14;
818
+ _context8.next = 17;
805
819
  return _axios["default"].post(process.env.authorityUri + "/connect/token", body, {
806
820
  headers: headers
807
821
  });
808
- case 16:
822
+ case 17:
809
823
  response = _context8.sent;
810
824
  domainHost = window.location.hostname.split(".").slice(-2).join(".");
811
825
  window.localStorage.removeItem("verifier");
812
- _context8.next = 21;
813
- return setCookie("access_token", response.data.access_token, {
814
- maxAge: 60 * 60 * 24 * 365,
826
+ _jsCookie["default"].set("access_token", response.data.access_token, {
827
+ expires: 365,
815
828
  path: "/",
816
829
  domain: domainHost,
817
830
  secure: true
818
831
  });
819
- case 21:
820
- _context8.next = 23;
821
- return setCookie("expires_in", response.data.expires_in, {
822
- maxAge: 60 * 60 * 24 * 365,
832
+ _jsCookie["default"].set("expires_in", String(response.data.expires_in), {
833
+ expires: 365,
823
834
  path: "/",
824
835
  domain: domainHost,
825
836
  secure: true
826
837
  });
827
- case 23:
828
- _context8.next = 25;
829
- return setCookie("refresh_token", response.data.refresh_token, {
830
- maxAge: 60 * 60 * 24 * 365,
838
+ _jsCookie["default"].set("refresh_token", response.data.refresh_token, {
839
+ expires: 365,
831
840
  path: "/",
832
841
  domain: domainHost,
833
842
  secure: true
834
843
  });
835
- case 25:
844
+ resetRedirectCounter();
836
845
  redirectUri = window.localStorage.getItem("redirectUri") || "/";
837
846
  window.localStorage.clear();
838
847
  window.location.href = redirectUri;
839
- _context8.next = 36;
848
+ _context8.next = 35;
840
849
  break;
841
- case 30:
842
- _context8.prev = 30;
843
- _context8.t0 = _context8["catch"](13);
850
+ case 29:
851
+ _context8.prev = 29;
852
+ _context8.t0 = _context8["catch"](14);
844
853
  console.error("PKCE sign-in failed", _context8.t0);
845
854
  window.localStorage.clear();
846
855
  setIsSigningIn(false);
847
- module.exports.authService().login();
848
- case 36:
856
+ setFrontEndLoadedState(true);
857
+ case 35:
849
858
  case "end":
850
859
  return _context8.stop();
851
860
  }
852
- }, _callee8, null, [[13, 30]]);
861
+ }, _callee8, null, [[14, 29]]);
853
862
  }));
854
863
  return function signInValidator(_x4) {
855
864
  return _ref11.apply(this, arguments);
@@ -960,7 +969,12 @@ function AuthScapeApp(_ref10) {
960
969
  };
961
970
  }, [frontEndLoadedState, pageProps.googleAnalytics4Code, pageProps.microsoftClarityCode]);
962
971
  (0, _react.useEffect)(function () {
963
- 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;
964
978
  module.exports.authService().login();
965
979
  }
966
980
  }, [signedInUserState, enforceLoggedIn, frontEndLoadedState, pathname]);
@@ -9598,19 +9612,6 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
9598
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; }
9599
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); }
9600
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); }); }; }
9601
- // Cookie utility function
9602
- var setCookie = function setCookie(name, value) {
9603
- var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
9604
- return new Promise(function (resolve) {
9605
- var cookieString = "".concat(name, "=").concat(value, ";");
9606
- if (options.maxAge) cookieString += "max-age=".concat(options.maxAge, ";");
9607
- if (options.path) cookieString += "path=".concat(options.path, ";");
9608
- if (options.domain) cookieString += "domain=".concat(options.domain, ";");
9609
- if (options.secure) cookieString += "secure;";
9610
- document.cookie = cookieString;
9611
- resolve();
9612
- });
9613
- };
9614
9615
  var setupDefaultOptions = /*#__PURE__*/function () {
9615
9616
  var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
9616
9617
  var ctx,
@@ -9657,9 +9658,16 @@ var RefreshToken = /*#__PURE__*/function () {
9657
9658
  return _regeneratorRuntime().wrap(function _callee2$(_context2) {
9658
9659
  while (1) switch (_context2.prev = _context2.next) {
9659
9660
  case 0:
9661
+ _context2.prev = 0;
9660
9662
  accessToken = _jsCookie["default"].get('access_token') || '';
9661
9663
  refreshToken = _jsCookie["default"].get('refresh_token') || '';
9662
- _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;
9663
9671
  return instance.post(process.env.authorityUri + "/connect/token", _queryString["default"].stringify({
9664
9672
  grant_type: 'refresh_token',
9665
9673
  client_id: process.env.client_id,
@@ -9671,42 +9679,44 @@ var RefreshToken = /*#__PURE__*/function () {
9671
9679
  "Authorization": "Bearer " + accessToken
9672
9680
  }
9673
9681
  });
9674
- case 4:
9682
+ case 7:
9675
9683
  response = _context2.sent;
9676
9684
  if (!(response != null && response.status == 200)) {
9677
- _context2.next = 14;
9685
+ _context2.next = 15;
9678
9686
  break;
9679
9687
  }
9680
9688
  domainHost = window.location.hostname.split('.').slice(-2).join('.');
9681
9689
  originalRequest.headers['Authorization'] = 'Bearer ' + response.data.access_token;
9682
- _context2.next = 10;
9683
- return setCookie('access_token', response.data.access_token, {
9684
- maxAge: 60 * 60 * 24 * 365,
9690
+ _jsCookie["default"].set('access_token', response.data.access_token, {
9691
+ expires: 365,
9685
9692
  path: '/',
9686
9693
  domain: domainHost,
9687
9694
  secure: true
9688
9695
  });
9689
- case 10:
9690
- _context2.next = 12;
9691
- return setCookie('expires_in', response.data.expires_in, {
9692
- maxAge: 60 * 60 * 24 * 365,
9696
+ _jsCookie["default"].set('expires_in', String(response.data.expires_in), {
9697
+ expires: 365,
9693
9698
  path: '/',
9694
9699
  domain: domainHost,
9695
9700
  secure: true
9696
9701
  });
9697
- case 12:
9698
- _context2.next = 14;
9699
- return setCookie('refresh_token', response.data.refresh_token, {
9700
- maxAge: 60 * 60 * 24 * 365,
9702
+ _jsCookie["default"].set('refresh_token', response.data.refresh_token, {
9703
+ expires: 365,
9701
9704
  path: '/',
9702
9705
  domain: domainHost,
9703
9706
  secure: true
9704
9707
  });
9705
- 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:
9706
9716
  case "end":
9707
9717
  return _context2.stop();
9708
9718
  }
9709
- }, _callee2);
9719
+ }, _callee2, null, [[0, 18]]);
9710
9720
  }));
9711
9721
  return function RefreshToken(_x, _x2) {
9712
9722
  return _ref2.apply(this, arguments);
@@ -9727,48 +9737,58 @@ var apiService = exports.apiService = function apiService() {
9727
9737
  return response;
9728
9738
  }, /*#__PURE__*/function () {
9729
9739
  var _ref3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee3(error) {
9730
- var originalConfig, domainHost;
9740
+ var originalConfig, refreshed, domainHost;
9731
9741
  return _regeneratorRuntime().wrap(function _callee3$(_context3) {
9732
9742
  while (1) switch (_context3.prev = _context3.next) {
9733
9743
  case 0:
9734
9744
  originalConfig = error.config;
9735
9745
  if (!error.response) {
9736
- _context3.next = 10;
9746
+ _context3.next = 13;
9737
9747
  break;
9738
9748
  }
9739
9749
  if (!(error.response.status === 401 && !originalConfig._retry)) {
9740
- _context3.next = 7;
9750
+ _context3.next = 10;
9741
9751
  break;
9742
9752
  }
9743
9753
  originalConfig._retry = true;
9744
9754
  _context3.next = 6;
9745
9755
  return RefreshToken(originalConfig, instance);
9746
9756
  case 6:
9757
+ refreshed = _context3.sent;
9758
+ if (!refreshed) {
9759
+ _context3.next = 9;
9760
+ break;
9761
+ }
9747
9762
  return _context3.abrupt("return", instance.request(originalConfig));
9748
- case 7:
9763
+ case 9:
9764
+ return _context3.abrupt("return", Promise.reject(error));
9765
+ case 10:
9749
9766
  if (!(error.response.status === 400)) {
9750
- _context3.next = 10;
9767
+ _context3.next = 13;
9751
9768
  break;
9752
9769
  }
9753
9770
  if (error.response.config.url.includes("/connect/token")) {
9754
9771
  domainHost = window.location.hostname.split('.').slice(-2).join('.');
9755
9772
  _jsCookie["default"].remove('access_token', {
9756
9773
  path: '/',
9757
- domain: domainHost
9774
+ domain: domainHost,
9775
+ secure: true
9758
9776
  });
9759
9777
  _jsCookie["default"].remove('refresh_token', {
9760
9778
  path: '/',
9761
- domain: domainHost
9779
+ domain: domainHost,
9780
+ secure: true
9762
9781
  });
9763
9782
  _jsCookie["default"].remove('expires_in', {
9764
9783
  path: '/',
9765
- domain: domainHost
9784
+ domain: domainHost,
9785
+ secure: true
9766
9786
  });
9767
9787
  }
9768
9788
  return _context3.abrupt("return", Promise.reject(error));
9769
- case 10:
9789
+ case 13:
9770
9790
  return _context3.abrupt("return", Promise.reject(error));
9771
- case 11:
9791
+ case 14:
9772
9792
  case "end":
9773
9793
  return _context3.stop();
9774
9794
  }
@@ -10317,15 +10337,18 @@ var _authService = exports.authService = function authService() {
10317
10337
  AuthUri = process.env.authorityUri;
10318
10338
  _jsCookie["default"].remove('access_token', {
10319
10339
  path: '/',
10320
- domain: domainHost
10340
+ domain: domainHost,
10341
+ secure: true
10321
10342
  });
10322
10343
  _jsCookie["default"].remove('refresh_token', {
10323
10344
  path: '/',
10324
- domain: domainHost
10345
+ domain: domainHost,
10346
+ secure: true
10325
10347
  });
10326
10348
  _jsCookie["default"].remove('expires_in', {
10327
10349
  path: '/',
10328
- domain: domainHost
10350
+ domain: domainHost,
10351
+ secure: true
10329
10352
  });
10330
10353
 
10331
10354
  // destroyCookie({}, "access_token", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "authscape",
3
- "version": "1.0.764",
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,9 +499,10 @@ 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
- const queryCode = searchParams.get("code");
505
+ const queryCode = searchParams?.get("code") ?? null;
490
506
  const pathname = usePathname();
491
507
 
492
508
  const signInValidator = async (codeFromQuery) => {
@@ -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", {