tenneo-auth-plugin 0.1.7 → 0.1.9
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/README.md +22 -45
- package/dist/index.d.mts +48 -66
- package/dist/index.d.ts +48 -66
- package/dist/index.js +334 -383
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +335 -381
- package/dist/index.mjs.map +1 -1
- package/package.json +53 -53
package/dist/index.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var zod = require('zod');
|
|
4
3
|
var axios = require('axios');
|
|
5
4
|
var react = require('react');
|
|
6
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
6
|
|
|
8
|
-
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
9
7
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
8
|
|
|
11
9
|
var axios__default = /*#__PURE__*/_interopDefault(axios);
|
|
@@ -74,13 +72,11 @@ function extractTenantKeyFromUrl(url, config, getStorage3, getKey) {
|
|
|
74
72
|
if (keyFromHost) return keyFromHost;
|
|
75
73
|
const clientCode = config.getClientCode();
|
|
76
74
|
if (clientCode?.trim()) return clientCode.trim();
|
|
77
|
-
const tenantId = config.getTenantId();
|
|
78
|
-
if (tenantId?.trim()) return tenantId.trim();
|
|
79
75
|
return config.getClientCode();
|
|
80
76
|
} catch {
|
|
81
77
|
const clientCode = config.getClientCode();
|
|
82
78
|
if (clientCode?.trim()) return clientCode.trim();
|
|
83
|
-
return config.
|
|
79
|
+
return config.getClientCode();
|
|
84
80
|
}
|
|
85
81
|
}
|
|
86
82
|
function isCallbackUrlFromUrl(url) {
|
|
@@ -811,85 +807,6 @@ function generateState() {
|
|
|
811
807
|
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
812
808
|
}
|
|
813
809
|
|
|
814
|
-
// src/config/env.ts
|
|
815
|
-
var ENV_KEYS = {
|
|
816
|
-
CLIENT_ID: ["VITE_CLIENT_ID", "CLIENT_ID"],
|
|
817
|
-
TENANT_ID: ["VITE_TENANT_ID", "TENANT_ID"],
|
|
818
|
-
CLIENTCODE: ["VITE_CLIENTCODE", "CLIENTCODE"]
|
|
819
|
-
};
|
|
820
|
-
function getEnvValue(keys) {
|
|
821
|
-
try {
|
|
822
|
-
const g = typeof globalThis !== "undefined" ? globalThis : null;
|
|
823
|
-
const env = g?.process && typeof g.process.env === "object" ? g.process.env : null;
|
|
824
|
-
if (env) {
|
|
825
|
-
for (const key of keys) {
|
|
826
|
-
const v = env[key];
|
|
827
|
-
if (v != null && String(v).trim()) return String(v).trim();
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
} catch {
|
|
831
|
-
}
|
|
832
|
-
try {
|
|
833
|
-
const meta = typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)) }) !== "undefined" ? undefined : void 0;
|
|
834
|
-
if (meta) {
|
|
835
|
-
for (const key of keys) {
|
|
836
|
-
const v = meta[key];
|
|
837
|
-
if (v != null && String(v).trim()) return String(v).trim();
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
} catch {
|
|
841
|
-
}
|
|
842
|
-
return "";
|
|
843
|
-
}
|
|
844
|
-
var FORBIDDEN_WINDOW_KEYS = ["apiBaseUrl", "apiTenantResolutionBaseUrl", "apiAuthBaseUrl", "authServerUrl", "defaultDomain", "API_BASE_URL", "AUTH_SERVER_URL", "DEFAULT_DOMAIN"];
|
|
845
|
-
function getWindowConfigRaw() {
|
|
846
|
-
if (typeof window === "undefined") return null;
|
|
847
|
-
const w = window;
|
|
848
|
-
const raw = w.__AUTH_CONFIG__ ?? w.__APP_CONFIG__;
|
|
849
|
-
if (!raw || typeof raw !== "object") return null;
|
|
850
|
-
for (const forbidden of FORBIDDEN_WINDOW_KEYS) {
|
|
851
|
-
if (forbidden in raw) {
|
|
852
|
-
throw new Error("Attempted to override protected internal configuration");
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
const out = {};
|
|
856
|
-
const map = {
|
|
857
|
-
clientId: "CLIENT_ID",
|
|
858
|
-
tenantId: "TENANT_ID",
|
|
859
|
-
clientcode: "CLIENTCODE"
|
|
860
|
-
};
|
|
861
|
-
for (const [winKey, sdkKey] of Object.entries(map)) {
|
|
862
|
-
const v = raw[winKey];
|
|
863
|
-
if (v != null && typeof v === "string" && v.trim()) out[sdkKey] = v.trim();
|
|
864
|
-
}
|
|
865
|
-
return Object.keys(out).length ? out : null;
|
|
866
|
-
}
|
|
867
|
-
function loadEnvConfig() {
|
|
868
|
-
const partial = {};
|
|
869
|
-
for (const [key, envKeys] of Object.entries(ENV_KEYS)) {
|
|
870
|
-
const v = getEnvValue(envKeys);
|
|
871
|
-
if (v) partial[key] = v;
|
|
872
|
-
}
|
|
873
|
-
return partial;
|
|
874
|
-
}
|
|
875
|
-
function loadWindowConfig() {
|
|
876
|
-
const raw = getWindowConfigRaw();
|
|
877
|
-
if (!raw) return null;
|
|
878
|
-
return raw;
|
|
879
|
-
}
|
|
880
|
-
var schema = zod.z.object({
|
|
881
|
-
CLIENT_ID: zod.z.string().min(1, "CLIENT_ID is required"),
|
|
882
|
-
TENANT_ID: zod.z.string().min(1, "TENANT_ID is required"),
|
|
883
|
-
CLIENTCODE: zod.z.string().min(1, "CLIENTCODE is required")
|
|
884
|
-
});
|
|
885
|
-
function validateConfig(data) {
|
|
886
|
-
return schema.parse(data);
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
// src/config/types.ts
|
|
890
|
-
var INTERNAL_CONFIG_KEYS = ["API_TENANT_RESOLUTION_BASE_URL", "API_AUTH_BASE_URL", "AUTH_SERVER_URL", "DEFAULT_DOMAIN"];
|
|
891
|
-
var RUNTIME_CONFIG_KEYS = ["CLIENT_ID", "TENANT_ID", "CLIENTCODE"];
|
|
892
|
-
|
|
893
810
|
// src/config/constants.ts
|
|
894
811
|
var OAUTH_CONSTANTS = {
|
|
895
812
|
SCOPES: "openid profile email",
|
|
@@ -917,232 +834,63 @@ var DEFAULT_TOKEN_GRANT_TYPE = OAUTH_CONSTANTS.TOKEN_GRANT_TYPE;
|
|
|
917
834
|
var DEFAULT_REFRESH_GRANT_TYPE = OAUTH_CONSTANTS.REFRESH_GRANT_TYPE;
|
|
918
835
|
|
|
919
836
|
// src/config/index.ts
|
|
920
|
-
var
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
}
|
|
941
|
-
function pickRuntimeConfig(source) {
|
|
942
|
-
if (!source) return {};
|
|
943
|
-
const picked = {};
|
|
944
|
-
for (const key of RUNTIME_CONFIG_KEYS) {
|
|
945
|
-
const value = source[key];
|
|
946
|
-
if (value != null && typeof value === "string") {
|
|
947
|
-
const trimmed = value.trim();
|
|
948
|
-
if (trimmed) picked[key] = trimmed;
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
return picked;
|
|
952
|
-
}
|
|
953
|
-
({
|
|
954
|
-
...INTERNAL_CONFIG,
|
|
955
|
-
...RUNTIME_CONFIG_DEFAULTS
|
|
956
|
-
});
|
|
957
|
-
var runtimeOverrides = {};
|
|
958
|
-
var runtimeConfigOverrides = {};
|
|
959
|
-
function mergeRuntime(base, ...sources) {
|
|
960
|
-
let out = { ...base };
|
|
961
|
-
for (const src of sources) {
|
|
962
|
-
if (!src) continue;
|
|
963
|
-
for (const key of Object.keys(src)) {
|
|
964
|
-
const value = src[key];
|
|
965
|
-
if (value != null && String(value).trim() !== "") out[key] = String(value).trim();
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
return out;
|
|
969
|
-
}
|
|
970
|
-
function assertNoInternalOverrides(source) {
|
|
971
|
-
if (!source) return;
|
|
972
|
-
for (const key of INTERNAL_CONFIG_KEYS) {
|
|
973
|
-
if (source[key] !== void 0) throw new Error("Attempted to override protected internal configuration");
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
var INTERNAL_KEY_SET = new Set(INTERNAL_CONFIG_KEYS);
|
|
977
|
-
var HOST_TO_RUNTIME_KEYS = {
|
|
978
|
-
clientId: "CLIENT_ID",
|
|
979
|
-
tenantId: "TENANT_ID",
|
|
980
|
-
clientcode: "CLIENTCODE"
|
|
981
|
-
};
|
|
982
|
-
function sanitizeRuntimeOverrides(source) {
|
|
983
|
-
if (!source) return void 0;
|
|
984
|
-
const filtered = {};
|
|
985
|
-
for (const [key, raw] of Object.entries(source)) {
|
|
986
|
-
if (raw == null) continue;
|
|
987
|
-
if (INTERNAL_KEY_SET.has(key)) continue;
|
|
988
|
-
const trimmed = String(raw).trim();
|
|
989
|
-
if (!trimmed) continue;
|
|
990
|
-
const sdkKey = HOST_TO_RUNTIME_KEYS[key] ?? key;
|
|
991
|
-
filtered[sdkKey] = trimmed;
|
|
992
|
-
}
|
|
993
|
-
const picked = pickRuntimeConfig(filtered);
|
|
994
|
-
return Object.keys(picked).length ? picked : void 0;
|
|
837
|
+
var inMemoryConfig = {};
|
|
838
|
+
function readHostConfigFromStorage() {
|
|
839
|
+
try {
|
|
840
|
+
const raw = getStorage(getStorageKey("host_config"));
|
|
841
|
+
if (!raw) return {};
|
|
842
|
+
const parsed = JSON.parse(raw);
|
|
843
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
844
|
+
} catch {
|
|
845
|
+
return {};
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
function resolveMerged(overrides) {
|
|
849
|
+
const stored = readHostConfigFromStorage();
|
|
850
|
+
const cfg = { ...stored, ...inMemoryConfig, ...overrides ?? {} };
|
|
851
|
+
const trimmed = (v) => v == null ? "" : String(v).trim();
|
|
852
|
+
return {
|
|
853
|
+
apiBaseUrl: trimmed(cfg.apiBaseUrl),
|
|
854
|
+
authServerUrl: trimmed(cfg.authServerUrl),
|
|
855
|
+
callbackUrl: trimmed(cfg.callbackUrl),
|
|
856
|
+
clientCode: trimmed(cfg.clientCode)
|
|
857
|
+
};
|
|
995
858
|
}
|
|
996
859
|
function resolveConfig(overrides) {
|
|
997
|
-
|
|
998
|
-
assertNoInternalOverrides(overrides);
|
|
999
|
-
const windowCfg = loadWindowConfig();
|
|
1000
|
-
const envCfg = loadEnvConfig();
|
|
1001
|
-
const mergedRuntime = mergeRuntime(
|
|
1002
|
-
RUNTIME_CONFIG_DEFAULTS,
|
|
1003
|
-
envCfg,
|
|
1004
|
-
windowCfg ?? void 0,
|
|
1005
|
-
runtimeOverrides,
|
|
1006
|
-
sanitizeRuntimeOverrides(overrides)
|
|
1007
|
-
);
|
|
1008
|
-
const validatedRuntime = validateConfig(mergedRuntime);
|
|
1009
|
-
return { ...INTERNAL_CONFIG, ...validatedRuntime };
|
|
860
|
+
return resolveMerged(overrides);
|
|
1010
861
|
}
|
|
1011
862
|
function getConfig() {
|
|
1012
|
-
return
|
|
863
|
+
return resolveMerged();
|
|
1013
864
|
}
|
|
1014
865
|
function setConfig(overrides) {
|
|
1015
|
-
|
|
1016
|
-
const sanitized = sanitizeRuntimeOverrides(overrides);
|
|
1017
|
-
if (sanitized) runtimeOverrides = { ...runtimeOverrides, ...sanitized };
|
|
1018
|
-
const { basePath, redirectUri } = overrides;
|
|
1019
|
-
if (basePath != null && basePath.trim() !== "") runtimeConfigOverrides = { ...runtimeConfigOverrides, basePath: basePath.trim() };
|
|
1020
|
-
if (redirectUri != null && redirectUri.trim() !== "") runtimeConfigOverrides = { ...runtimeConfigOverrides, redirectUri: redirectUri.trim() };
|
|
866
|
+
inMemoryConfig = { ...inMemoryConfig, ...overrides };
|
|
1021
867
|
}
|
|
1022
868
|
function clearConfigOverrides() {
|
|
1023
|
-
|
|
1024
|
-
runtimeConfigOverrides = {};
|
|
1025
|
-
}
|
|
1026
|
-
function getWindowBasePath() {
|
|
1027
|
-
if (typeof window === "undefined") return "";
|
|
1028
|
-
const w = window;
|
|
1029
|
-
const raw = w.__AUTH_CONFIG__ ?? w.__APP_CONFIG__;
|
|
1030
|
-
const bp = raw?.basePath;
|
|
1031
|
-
if (bp != null && typeof bp === "string" && bp.trim()) return bp.trim();
|
|
1032
|
-
const pathname = window.location.pathname;
|
|
1033
|
-
const segments = pathname.split("/").filter(Boolean);
|
|
1034
|
-
const commonRoutes = ["dashboards", "callback", "confirmation", "client-confirmed", "client-provisioned", "approval-completed"];
|
|
1035
|
-
if (segments.length > 0 && !commonRoutes.includes(segments[0])) {
|
|
1036
|
-
let base = "/" + segments[0];
|
|
1037
|
-
if (base.endsWith("/")) base = base.slice(0, -1);
|
|
1038
|
-
return base;
|
|
1039
|
-
}
|
|
1040
|
-
return "";
|
|
1041
|
-
}
|
|
1042
|
-
function getBasePath() {
|
|
1043
|
-
if (runtimeConfigOverrides.basePath != null && runtimeConfigOverrides.basePath !== "") return runtimeConfigOverrides.basePath;
|
|
1044
|
-
return getWindowBasePath();
|
|
869
|
+
inMemoryConfig = {};
|
|
1045
870
|
}
|
|
1046
871
|
function getRedirectUri2() {
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
}
|
|
1050
|
-
return
|
|
1051
|
-
}
|
|
1052
|
-
function hasRuntimeConfig() {
|
|
1053
|
-
return loadWindowConfig() !== null || Object.keys(runtimeOverrides).length > 0;
|
|
872
|
+
const cfg = resolveMerged();
|
|
873
|
+
if (cfg.callbackUrl) return cfg.callbackUrl;
|
|
874
|
+
if (typeof window !== "undefined") return `${window.location.origin}/callback`;
|
|
875
|
+
return "";
|
|
1054
876
|
}
|
|
1055
877
|
var Config = {
|
|
1056
|
-
|
|
1057
|
-
return
|
|
1058
|
-
},
|
|
1059
|
-
getApiAuthBaseUrl() {
|
|
1060
|
-
return getConfig().API_AUTH_BASE_URL;
|
|
878
|
+
getApiBaseUrl() {
|
|
879
|
+
return resolveMerged().apiBaseUrl;
|
|
1061
880
|
},
|
|
1062
881
|
getAuthServerUrl() {
|
|
1063
|
-
return
|
|
1064
|
-
},
|
|
1065
|
-
getDefaultDomain() {
|
|
1066
|
-
return getConfig().DEFAULT_DOMAIN;
|
|
1067
|
-
},
|
|
1068
|
-
getClientId() {
|
|
1069
|
-
return getConfig().CLIENT_ID;
|
|
1070
|
-
},
|
|
1071
|
-
getTenantId() {
|
|
1072
|
-
return getConfig().TENANT_ID;
|
|
882
|
+
return resolveMerged().authServerUrl;
|
|
1073
883
|
},
|
|
1074
884
|
getClientCode() {
|
|
1075
|
-
return
|
|
885
|
+
return resolveMerged().clientCode;
|
|
1076
886
|
},
|
|
1077
887
|
getRedirectUri() {
|
|
1078
888
|
return getRedirectUri2();
|
|
1079
889
|
},
|
|
1080
|
-
getBasePath() {
|
|
1081
|
-
return getBasePath();
|
|
1082
|
-
},
|
|
1083
|
-
hasRuntimeConfig() {
|
|
1084
|
-
return hasRuntimeConfig();
|
|
1085
|
-
},
|
|
1086
890
|
getAll() {
|
|
1087
|
-
|
|
1088
|
-
return {
|
|
1089
|
-
apiTenantResolutionBaseUrl: c.API_TENANT_RESOLUTION_BASE_URL,
|
|
1090
|
-
apiAuthBaseUrl: c.API_AUTH_BASE_URL,
|
|
1091
|
-
authServerUrl: c.AUTH_SERVER_URL,
|
|
1092
|
-
defaultDomain: c.DEFAULT_DOMAIN,
|
|
1093
|
-
clientId: c.CLIENT_ID,
|
|
1094
|
-
tenantId: c.TENANT_ID,
|
|
1095
|
-
clientCode: c.CLIENTCODE,
|
|
1096
|
-
redirectUri: getRedirectUri2(),
|
|
1097
|
-
basePath: getBasePath()
|
|
1098
|
-
};
|
|
891
|
+
return resolveMerged();
|
|
1099
892
|
}
|
|
1100
893
|
};
|
|
1101
|
-
({
|
|
1102
|
-
AUTH_SERVER_URL: Config.getAuthServerUrl(),
|
|
1103
|
-
CLIENT_ID: Config.getClientId(),
|
|
1104
|
-
TENANT_ID: Config.getTenantId(),
|
|
1105
|
-
CLIENTCODE: Config.getClientCode()
|
|
1106
|
-
});
|
|
1107
|
-
function getEnvConfig() {
|
|
1108
|
-
const authServerUrl = Config.getAuthServerUrl();
|
|
1109
|
-
const clientId = Config.getClientId();
|
|
1110
|
-
const tenantId = Config.getTenantId();
|
|
1111
|
-
const redirectUri = Config.getRedirectUri();
|
|
1112
|
-
try {
|
|
1113
|
-
new URL(authServerUrl);
|
|
1114
|
-
new URL(redirectUri);
|
|
1115
|
-
} catch {
|
|
1116
|
-
return Promise.resolve(null);
|
|
1117
|
-
}
|
|
1118
|
-
return Promise.resolve({
|
|
1119
|
-
authServerUrl: authServerUrl.trim(),
|
|
1120
|
-
clientId: clientId.trim(),
|
|
1121
|
-
redirectUri: redirectUri.trim(),
|
|
1122
|
-
tenantId: tenantId.trim()
|
|
1123
|
-
});
|
|
1124
|
-
}
|
|
1125
|
-
function getEnvConfigSync() {
|
|
1126
|
-
const authServerUrl = Config.getAuthServerUrl();
|
|
1127
|
-
const clientId = Config.getClientId();
|
|
1128
|
-
const tenantId = Config.getTenantId();
|
|
1129
|
-
const redirectUri = Config.getRedirectUri();
|
|
1130
|
-
try {
|
|
1131
|
-
new URL(authServerUrl);
|
|
1132
|
-
new URL(redirectUri);
|
|
1133
|
-
} catch {
|
|
1134
|
-
return null;
|
|
1135
|
-
}
|
|
1136
|
-
return {
|
|
1137
|
-
authServerUrl: authServerUrl.trim(),
|
|
1138
|
-
clientId: clientId.trim(),
|
|
1139
|
-
redirectUri: redirectUri.trim(),
|
|
1140
|
-
tenantId: tenantId.trim()
|
|
1141
|
-
};
|
|
1142
|
-
}
|
|
1143
|
-
function hasEnvFallback() {
|
|
1144
|
-
return getEnvConfigSync() !== null;
|
|
1145
|
-
}
|
|
1146
894
|
|
|
1147
895
|
// src/utils/validation.ts
|
|
1148
896
|
function isValidGuid(guid) {
|
|
@@ -1296,7 +1044,8 @@ function storeTenantConfig(config) {
|
|
|
1296
1044
|
if (!validation.isValid) {
|
|
1297
1045
|
logger.warn("Tenant ID validation failed", { tenantId: config.tenantId });
|
|
1298
1046
|
}
|
|
1299
|
-
|
|
1047
|
+
const authServerToStore = Config.getAuthServerUrl() || config.authServer;
|
|
1048
|
+
setStorage(STORAGE_KEYS.authServerUrl, authServerToStore);
|
|
1300
1049
|
setStorage(STORAGE_KEYS.clientId, config.client.clientId);
|
|
1301
1050
|
setStorage(STORAGE_KEYS.redirectUri, Config.getRedirectUri());
|
|
1302
1051
|
setStorage(STORAGE_KEYS.tenantId, config.tenantId);
|
|
@@ -1307,6 +1056,22 @@ function storeTenantConfig(config) {
|
|
|
1307
1056
|
async function initiateAuthFlow(config) {
|
|
1308
1057
|
try {
|
|
1309
1058
|
logger.info("Initiating OAuth authorization flow");
|
|
1059
|
+
const authServerFromProps = Config.getAuthServerUrl();
|
|
1060
|
+
const authServerEffective = (authServerFromProps || config?.authServer || "").replace(/\/+$/, "");
|
|
1061
|
+
const redirectUriEffective = Config.getRedirectUri();
|
|
1062
|
+
const storedTenantId = getStorage(STORAGE_KEYS.tenantId);
|
|
1063
|
+
const storedClientId = getStorage(STORAGE_KEYS.clientId);
|
|
1064
|
+
const tenantIdEffective = storedTenantId || config?.tenantId || "";
|
|
1065
|
+
const clientIdEffective = storedClientId || config?.client?.clientId || "";
|
|
1066
|
+
logger.debug("[initiateAuthFlow] Resolved inputs", {
|
|
1067
|
+
authServerFromProps: authServerFromProps ? "(provided)" : "(empty)",
|
|
1068
|
+
authServerEffective,
|
|
1069
|
+
redirectUriEffective,
|
|
1070
|
+
tenantIdEffective,
|
|
1071
|
+
clientIdEffective,
|
|
1072
|
+
scopes: config?.client?.scopes,
|
|
1073
|
+
hasRuntime: !!getAuthRuntime()
|
|
1074
|
+
});
|
|
1310
1075
|
const token = getAccessToken();
|
|
1311
1076
|
if (token && !isAccessTokenExpired()) {
|
|
1312
1077
|
logger.debug("Valid token already exists, skipping auth flow");
|
|
@@ -1328,10 +1093,17 @@ async function initiateAuthFlow(config) {
|
|
|
1328
1093
|
}
|
|
1329
1094
|
}
|
|
1330
1095
|
setFlowFlags();
|
|
1331
|
-
if (!config?.authServer || !config.client?.clientId || !config.client?.redirectUri) {
|
|
1096
|
+
if (!(Config.getAuthServerUrl() || config?.authServer) || !config.client?.clientId || !config.client?.redirectUri) {
|
|
1097
|
+
logger.error("[initiateAuthFlow] Missing required tenant config", {
|
|
1098
|
+
authServerEffective,
|
|
1099
|
+
clientId: config?.client?.clientId,
|
|
1100
|
+
redirectUriFromTenantApi: config?.client?.redirectUri,
|
|
1101
|
+
redirectUriEffective
|
|
1102
|
+
});
|
|
1332
1103
|
throw new Error("Invalid tenant configuration for auth flow");
|
|
1333
1104
|
}
|
|
1334
1105
|
storeTenantConfig(config);
|
|
1106
|
+
logger.debug("[initiateAuthFlow] Stored tenant config, generating PKCE");
|
|
1335
1107
|
const codeVerifier = generateCodeVerifier();
|
|
1336
1108
|
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
|
1337
1109
|
const state = generateState();
|
|
@@ -1340,6 +1112,10 @@ async function initiateAuthFlow(config) {
|
|
|
1340
1112
|
setStorage(STORAGE_KEYS.codeVerifier, codeVerifier);
|
|
1341
1113
|
setStorage(STORAGE_KEYS.state, state);
|
|
1342
1114
|
const authUrl = buildAuthorizationUrl(config, codeChallenge, state);
|
|
1115
|
+
logger.debug("[initiateAuthFlow] Built authorization URL", {
|
|
1116
|
+
authServerEffective,
|
|
1117
|
+
urlPrefix: authUrl?.slice(0, 80)
|
|
1118
|
+
});
|
|
1343
1119
|
if (!authUrl || !(authUrl.startsWith("http://") || authUrl.startsWith("https://"))) {
|
|
1344
1120
|
throw new Error("Invalid authorization URL generated");
|
|
1345
1121
|
}
|
|
@@ -1351,8 +1127,15 @@ async function initiateAuthFlow(config) {
|
|
|
1351
1127
|
logger.info("Redirecting to authorization server");
|
|
1352
1128
|
emitAuthEvent(AuthEventNames.LOGIN_STARTED, { tenantKey: config.tenantKey });
|
|
1353
1129
|
const runtime = getAuthRuntime();
|
|
1354
|
-
if (runtime)
|
|
1355
|
-
|
|
1130
|
+
if (runtime) {
|
|
1131
|
+
logger.debug("[initiateAuthFlow] Redirect via runtime.urlProvider.redirect");
|
|
1132
|
+
runtime.urlProvider.redirect(authUrl);
|
|
1133
|
+
} else if (typeof window !== "undefined") {
|
|
1134
|
+
logger.debug("[initiateAuthFlow] Redirect via window.location.replace");
|
|
1135
|
+
window.location.replace(authUrl);
|
|
1136
|
+
} else {
|
|
1137
|
+
logger.error("[initiateAuthFlow] No runtime and no window; cannot redirect", { authUrl });
|
|
1138
|
+
}
|
|
1356
1139
|
} catch (error) {
|
|
1357
1140
|
clearFlowFlags();
|
|
1358
1141
|
logger.error("Failed to initiate auth flow", {
|
|
@@ -1362,9 +1145,10 @@ async function initiateAuthFlow(config) {
|
|
|
1362
1145
|
}
|
|
1363
1146
|
}
|
|
1364
1147
|
function buildAuthorizationUrl(config, codeChallenge, state) {
|
|
1148
|
+
const authServerBase = (Config.getAuthServerUrl() || config.authServer || "").replace(/\/+$/, "");
|
|
1365
1149
|
if (isLocalhost2()) {
|
|
1366
1150
|
logger.debug("Building authorization URL", {
|
|
1367
|
-
authServer:
|
|
1151
|
+
authServer: authServerBase,
|
|
1368
1152
|
clientId: config.client.clientId,
|
|
1369
1153
|
redirectUri: config.client.redirectUri,
|
|
1370
1154
|
scopes: config.client.scopes
|
|
@@ -1385,7 +1169,7 @@ function buildAuthorizationUrl(config, codeChallenge, state) {
|
|
|
1385
1169
|
code_challenge: codeChallenge,
|
|
1386
1170
|
code_challenge_method: DEFAULT_CODE_CHALLENGE_METHOD
|
|
1387
1171
|
});
|
|
1388
|
-
return `${
|
|
1172
|
+
return `${authServerBase}/connect/authorize?${params.toString()}`;
|
|
1389
1173
|
}
|
|
1390
1174
|
|
|
1391
1175
|
// src/strategies/oauth2-pkce/token-exchange.ts
|
|
@@ -1415,7 +1199,7 @@ function storeTokens(tokenData) {
|
|
|
1415
1199
|
async function exchangeCodeForTokens(params) {
|
|
1416
1200
|
try {
|
|
1417
1201
|
const { code, codeVerifier, clientId, redirectUri } = params;
|
|
1418
|
-
const apiAuthBaseUrl = Config.
|
|
1202
|
+
const apiAuthBaseUrl = Config.getAuthServerUrl();
|
|
1419
1203
|
const tokenUrl = `${apiAuthBaseUrl}/oauth/token`;
|
|
1420
1204
|
const body = new URLSearchParams({
|
|
1421
1205
|
grant_type: DEFAULT_TOKEN_GRANT_TYPE,
|
|
@@ -1489,7 +1273,7 @@ async function refreshAccessToken() {
|
|
|
1489
1273
|
});
|
|
1490
1274
|
throw new Error("Cannot refresh token: missing required data");
|
|
1491
1275
|
}
|
|
1492
|
-
const apiAuthBaseUrl = Config.
|
|
1276
|
+
const apiAuthBaseUrl = Config.getApiBaseUrl();
|
|
1493
1277
|
const tokenUrl = `${apiAuthBaseUrl}/oauth/refresh`;
|
|
1494
1278
|
const body = new URLSearchParams({
|
|
1495
1279
|
grant_type: DEFAULT_REFRESH_GRANT_TYPE,
|
|
@@ -1886,40 +1670,15 @@ function mergeConfigWithProps(apiEnvConfig, propsConfig, tenantKey) {
|
|
|
1886
1670
|
}
|
|
1887
1671
|
};
|
|
1888
1672
|
}
|
|
1889
|
-
async function buildTenantConfigFromEnv() {
|
|
1890
|
-
const envConfig = await getEnvConfig();
|
|
1891
|
-
if (!envConfig) return null;
|
|
1892
|
-
return {
|
|
1893
|
-
tenantId: envConfig.tenantId,
|
|
1894
|
-
authServer: envConfig.authServerUrl,
|
|
1895
|
-
client: {
|
|
1896
|
-
clientId: envConfig.clientId,
|
|
1897
|
-
redirectUri: envConfig.redirectUri,
|
|
1898
|
-
scopes: "openid profile email"
|
|
1899
|
-
}
|
|
1900
|
-
};
|
|
1901
|
-
}
|
|
1902
1673
|
async function resolveTenantConfig(tenantKey, tenantResolver) {
|
|
1903
1674
|
if (!tenantKey) return null;
|
|
1904
1675
|
const propsConfig = getPropsConfig();
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
apiEnvConfig = await tenantResolver.resolve(tenantKey);
|
|
1908
|
-
apiResolved = !!apiEnvConfig;
|
|
1909
|
-
if (!apiEnvConfig) {
|
|
1910
|
-
apiEnvConfig = await buildTenantConfigFromEnv();
|
|
1911
|
-
}
|
|
1912
|
-
if (!apiEnvConfig) return null;
|
|
1913
|
-
if (!apiResolved && propsConfig) {
|
|
1914
|
-
const mergedConfig = mergeConfigWithProps(apiEnvConfig, propsConfig, tenantKey);
|
|
1915
|
-
removeStorage(getStorageKey("props_config"));
|
|
1916
|
-
logger.info("Merged props config with ENV fallback config");
|
|
1917
|
-
return mergedConfig;
|
|
1918
|
-
}
|
|
1676
|
+
const resolved = await tenantResolver.resolve(tenantKey);
|
|
1677
|
+
if (!resolved) return null;
|
|
1919
1678
|
removeStorage(getStorageKey("props_config"));
|
|
1920
1679
|
return {
|
|
1921
|
-
...
|
|
1922
|
-
tenantKey: tenantKey ||
|
|
1680
|
+
...propsConfig ? mergeConfigWithProps(resolved, propsConfig, tenantKey) : resolved,
|
|
1681
|
+
tenantKey: tenantKey || resolved.tenantKey
|
|
1923
1682
|
};
|
|
1924
1683
|
}
|
|
1925
1684
|
async function resolveTenantConfigCached(tenantKey, tenantResolver) {
|
|
@@ -2113,6 +1872,8 @@ var LoginFlow = class {
|
|
|
2113
1872
|
const { runtime } = context;
|
|
2114
1873
|
const { logger: log } = runtime;
|
|
2115
1874
|
const getUrl = () => runtime.urlProvider.getCurrentUrl();
|
|
1875
|
+
const url = getUrl();
|
|
1876
|
+
log.debug("[LoginFlow] Start", { url: url.href, pathname: url.pathname, search: url.search });
|
|
2116
1877
|
const callbackProcessed = getStorage(getStorageKey("callback_processed")) === "true";
|
|
2117
1878
|
const token = getAccessToken();
|
|
2118
1879
|
if (callbackProcessed && !token) {
|
|
@@ -2122,7 +1883,8 @@ var LoginFlow = class {
|
|
|
2122
1883
|
}
|
|
2123
1884
|
const wasStateMismatch = getStorage(getStorageKey("state_mismatch")) === "true";
|
|
2124
1885
|
if (wasStateMismatch) removeStorage(getStorageKey("state_mismatch"));
|
|
2125
|
-
const tenantKey = getTenantKeyFromRuntime(
|
|
1886
|
+
const tenantKey = getTenantKeyFromRuntime(url, runtime.configProvider);
|
|
1887
|
+
log.debug("[LoginFlow] Tenant key resolved", { tenantKey: tenantKey ?? "(null)" });
|
|
2126
1888
|
if (!tenantKey) {
|
|
2127
1889
|
throw new SanitizedError(
|
|
2128
1890
|
"TENANT_KEY_RESOLUTION_FAILED",
|
|
@@ -2130,7 +1892,15 @@ var LoginFlow = class {
|
|
|
2130
1892
|
new Error("Tenant key missing")
|
|
2131
1893
|
);
|
|
2132
1894
|
}
|
|
1895
|
+
log.debug("[LoginFlow] Resolving tenant config", { tenantKey });
|
|
2133
1896
|
const tenantConfig = await resolveTenantConfigCached(tenantKey, runtime.tenantResolver);
|
|
1897
|
+
log.debug("[LoginFlow] Tenant config resolved", {
|
|
1898
|
+
ok: !!tenantConfig,
|
|
1899
|
+
tenantId: tenantConfig?.tenantId,
|
|
1900
|
+
authServer: tenantConfig?.authServer ? "(set)" : "(empty)",
|
|
1901
|
+
clientId: tenantConfig?.client?.clientId,
|
|
1902
|
+
redirectUri: tenantConfig?.client?.redirectUri
|
|
1903
|
+
});
|
|
2134
1904
|
if (!tenantConfig) {
|
|
2135
1905
|
throw new SanitizedError(
|
|
2136
1906
|
"TENANT_CONFIG_RESOLUTION_FAILED",
|
|
@@ -2140,7 +1910,9 @@ var LoginFlow = class {
|
|
|
2140
1910
|
}
|
|
2141
1911
|
setTenantKey(tenantKey);
|
|
2142
1912
|
storeTenantConfig(tenantConfig);
|
|
1913
|
+
log.debug("[LoginFlow] Stored tenant config, initiating auth flow");
|
|
2143
1914
|
await initiateAuthFlow(tenantConfig);
|
|
1915
|
+
log.debug("[LoginFlow] Auth flow initiated (redirect should happen)");
|
|
2144
1916
|
return { completed: true };
|
|
2145
1917
|
}
|
|
2146
1918
|
};
|
|
@@ -2489,7 +2261,74 @@ function resetCookieWatcher() {
|
|
|
2489
2261
|
authCookies
|
|
2490
2262
|
});
|
|
2491
2263
|
}
|
|
2264
|
+
|
|
2265
|
+
// src/infrastructure/watchers/storage-watcher.ts
|
|
2266
|
+
var isWatching2 = false;
|
|
2267
|
+
var lastStorageCheck = null;
|
|
2268
|
+
var storageEventListener = null;
|
|
2269
|
+
function checkStorageCleared() {
|
|
2270
|
+
try {
|
|
2271
|
+
const hasAnyAuthData = Object.values(STORAGE_KEYS).some(
|
|
2272
|
+
(key) => getStorage(key) !== null
|
|
2273
|
+
);
|
|
2274
|
+
if (lastStorageCheck === "had_data" && !hasAnyAuthData) return true;
|
|
2275
|
+
lastStorageCheck = hasAnyAuthData ? "had_data" : "no_data";
|
|
2276
|
+
return false;
|
|
2277
|
+
} catch {
|
|
2278
|
+
return false;
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
function handleStorageEvent(event) {
|
|
2282
|
+
if (typeof window !== "undefined" && event.storageArea === window.sessionStorage) {
|
|
2283
|
+
const wasCleared = checkStorageCleared();
|
|
2284
|
+
if (wasCleared) {
|
|
2285
|
+
logger.info("Detected manual sessionStorage clear! Redirecting to login...");
|
|
2286
|
+
const cb = getSessionClearedCallback();
|
|
2287
|
+
if (cb) {
|
|
2288
|
+
Promise.resolve(cb()).catch((error) => {
|
|
2289
|
+
logger.error("Failed to redirect to login after manual clear", {
|
|
2290
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2291
|
+
});
|
|
2292
|
+
});
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
function startStorageWatcher() {
|
|
2298
|
+
if (isWatching2) return;
|
|
2299
|
+
isWatching2 = true;
|
|
2300
|
+
checkStorageCleared();
|
|
2301
|
+
storageEventListener = handleStorageEvent;
|
|
2302
|
+
window.addEventListener("storage", storageEventListener);
|
|
2303
|
+
const pollInterval = setInterval(() => {
|
|
2304
|
+
const logoutInProgress = typeof window !== "undefined" && window.localStorage.getItem(getStorageKey("logout_in_progress")) === "true";
|
|
2305
|
+
if (logoutInProgress) {
|
|
2306
|
+
logger.debug("Logout detected. Storage watcher will not trigger bootstrap.");
|
|
2307
|
+
return;
|
|
2308
|
+
}
|
|
2309
|
+
const wasCleared = checkStorageCleared();
|
|
2310
|
+
if (wasCleared) {
|
|
2311
|
+
logger.info("Detected manual sessionStorage clear (polling)! Redirecting to login...");
|
|
2312
|
+
clearInterval(pollInterval);
|
|
2313
|
+
const cb = getSessionClearedCallback();
|
|
2314
|
+
if (cb) {
|
|
2315
|
+
Promise.resolve(cb()).catch((error) => {
|
|
2316
|
+
logger.error("Failed to redirect to login after manual clear", {
|
|
2317
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2318
|
+
});
|
|
2319
|
+
if (!isWatching2) startStorageWatcher();
|
|
2320
|
+
});
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
}, 1e3);
|
|
2324
|
+
window.__tenneo_auth_storage_watcher_interval = pollInterval;
|
|
2325
|
+
}
|
|
2492
2326
|
function stopStorageWatcher() {
|
|
2327
|
+
isWatching2 = false;
|
|
2328
|
+
if (storageEventListener) {
|
|
2329
|
+
window.removeEventListener("storage", storageEventListener);
|
|
2330
|
+
storageEventListener = null;
|
|
2331
|
+
}
|
|
2493
2332
|
const win = window;
|
|
2494
2333
|
const intervalId = win.__tenneo_auth_storage_watcher_interval;
|
|
2495
2334
|
if (intervalId) {
|
|
@@ -2539,51 +2378,68 @@ function buildUrl(baseUrl, path) {
|
|
|
2539
2378
|
url.pathname = url.pathname.endsWith("/") ? `${url.pathname}${normalizedPath.slice(1)}` : `${url.pathname}${normalizedPath}`;
|
|
2540
2379
|
return url.toString();
|
|
2541
2380
|
}
|
|
2542
|
-
|
|
2381
|
+
function getCsrfToken() {
|
|
2543
2382
|
try {
|
|
2383
|
+
if (typeof document === "undefined") return null;
|
|
2384
|
+
const meta = document.querySelector('meta[name="csrf-token"]');
|
|
2385
|
+
if (meta?.content) return meta.content;
|
|
2386
|
+
const match = document.cookie.match(/(?:^|;\s*)XSRF-TOKEN=([^;]+)/i);
|
|
2387
|
+
if (match) return decodeURIComponent(match[1]);
|
|
2388
|
+
return null;
|
|
2389
|
+
} catch {
|
|
2390
|
+
return null;
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
async function callServerLogout(logoutUrl) {
|
|
2394
|
+
const csrfToken = getCsrfToken();
|
|
2395
|
+
async function doRequest(method) {
|
|
2396
|
+
const isPost = method === "POST";
|
|
2397
|
+
const headers = {
|
|
2398
|
+
"X-Requested-With": "XMLHttpRequest",
|
|
2399
|
+
Accept: "application/json, */*"
|
|
2400
|
+
};
|
|
2401
|
+
if (isPost) {
|
|
2402
|
+
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
|
2403
|
+
}
|
|
2404
|
+
if (csrfToken) {
|
|
2405
|
+
headers["X-CSRF-Token"] = csrfToken;
|
|
2406
|
+
}
|
|
2544
2407
|
const response = await fetch(logoutUrl, {
|
|
2545
|
-
method
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
"X-Requested-With": "XMLHttpRequest",
|
|
2549
|
-
Accept: "application/json"
|
|
2550
|
-
},
|
|
2408
|
+
method,
|
|
2409
|
+
mode: "cors",
|
|
2410
|
+
headers,
|
|
2551
2411
|
credentials: "include"
|
|
2552
2412
|
});
|
|
2413
|
+
if (!response.ok) {
|
|
2414
|
+
logger.warn("Server logout HTTP error", {
|
|
2415
|
+
method,
|
|
2416
|
+
status: response.status,
|
|
2417
|
+
statusText: response.statusText
|
|
2418
|
+
});
|
|
2419
|
+
return { success: false };
|
|
2420
|
+
}
|
|
2553
2421
|
const data = await response.json().catch(() => ({}));
|
|
2554
|
-
logger.info(
|
|
2422
|
+
logger.info(`Server logout response (${method})`, { response: data });
|
|
2555
2423
|
if (data && (data.success === true || data.logout === true)) {
|
|
2556
2424
|
return { success: true, response: data };
|
|
2557
2425
|
}
|
|
2558
|
-
logger.warn("Server logout response invalid
|
|
2426
|
+
logger.warn("Server logout response invalid payload", {
|
|
2427
|
+
method,
|
|
2428
|
+
response: data
|
|
2429
|
+
});
|
|
2559
2430
|
return { success: false, response: data };
|
|
2431
|
+
}
|
|
2432
|
+
try {
|
|
2433
|
+
const postResult = await doRequest("POST");
|
|
2434
|
+
if (postResult.success) return postResult;
|
|
2435
|
+
logger.debug("POST logout did not succeed, trying GET");
|
|
2436
|
+
const getResult = await doRequest("GET");
|
|
2437
|
+
return getResult;
|
|
2560
2438
|
} catch (error) {
|
|
2561
|
-
logger.
|
|
2439
|
+
logger.warn("Server logout failed (both POST and GET)", {
|
|
2562
2440
|
error: error instanceof Error ? error.message : String(error)
|
|
2563
2441
|
});
|
|
2564
|
-
|
|
2565
|
-
const response = await fetch(logoutUrl, {
|
|
2566
|
-
method: "GET",
|
|
2567
|
-
headers: {
|
|
2568
|
-
"X-Requested-With": "XMLHttpRequest",
|
|
2569
|
-
Accept: "application/json"
|
|
2570
|
-
},
|
|
2571
|
-
credentials: "include"
|
|
2572
|
-
});
|
|
2573
|
-
const data = await response.json().catch(() => ({}));
|
|
2574
|
-
logger.info("Server logout response (GET)", { response: data });
|
|
2575
|
-
if (data && (data.success === true || data.logout === true)) {
|
|
2576
|
-
return { success: true, response: data };
|
|
2577
|
-
}
|
|
2578
|
-
logger.warn("Server logout response invalid (GET)", { response: data });
|
|
2579
|
-
return { success: false, response: data };
|
|
2580
|
-
} catch (getError) {
|
|
2581
|
-
logger.warn("Server logout failed (both POST and GET)", {
|
|
2582
|
-
postError: error instanceof Error ? error.message : String(error),
|
|
2583
|
-
getError: getError instanceof Error ? getError.message : String(getError)
|
|
2584
|
-
});
|
|
2585
|
-
return { success: false };
|
|
2586
|
-
}
|
|
2442
|
+
return { success: false };
|
|
2587
2443
|
}
|
|
2588
2444
|
}
|
|
2589
2445
|
function performLocalLogoutCleanup() {
|
|
@@ -2596,22 +2452,50 @@ function performLocalLogoutCleanup() {
|
|
|
2596
2452
|
});
|
|
2597
2453
|
}
|
|
2598
2454
|
clearClientCookies();
|
|
2599
|
-
|
|
2455
|
+
try {
|
|
2456
|
+
clearAuthStorage();
|
|
2457
|
+
} catch (error) {
|
|
2458
|
+
logger.warn("clearAuthStorage failed (ignored)", {
|
|
2459
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2460
|
+
});
|
|
2461
|
+
}
|
|
2600
2462
|
logger.info("Local logout cleanup completed");
|
|
2601
2463
|
}
|
|
2464
|
+
function acquireLogoutLock() {
|
|
2465
|
+
const LOCK_KEY = getStorageKey("logout_lock");
|
|
2466
|
+
const now = Date.now();
|
|
2467
|
+
const existingLock = getStorage(LOCK_KEY);
|
|
2468
|
+
if (existingLock) {
|
|
2469
|
+
const lockTime = Number(existingLock);
|
|
2470
|
+
if (!Number.isNaN(lockTime) && now - lockTime < 5e3) {
|
|
2471
|
+
logger.debug("Logout lock active \u2013 skipping duplicate logout", {
|
|
2472
|
+
now,
|
|
2473
|
+
lockTime
|
|
2474
|
+
});
|
|
2475
|
+
return false;
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2478
|
+
setStorage(LOCK_KEY, String(now));
|
|
2479
|
+
return true;
|
|
2480
|
+
}
|
|
2481
|
+
function releaseLogoutLock() {
|
|
2482
|
+
try {
|
|
2483
|
+
removeStorage(getStorageKey("logout_lock"));
|
|
2484
|
+
} catch {
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2602
2487
|
async function logout(tenantKey) {
|
|
2603
|
-
setStorage(getStorageKey("logout_in_progress"), "true");
|
|
2604
2488
|
setStorage(getStorageKey("force_login"), "true");
|
|
2605
|
-
if (tenantKey?.trim())
|
|
2606
|
-
|
|
2607
|
-
|
|
2489
|
+
if (tenantKey?.trim()) {
|
|
2490
|
+
setStorage(getStorageKey("preserved_tenant_key"), tenantKey.trim());
|
|
2491
|
+
}
|
|
2492
|
+
if (!acquireLogoutLock()) {
|
|
2608
2493
|
return { success: true, message: "Logout already in progress." };
|
|
2609
2494
|
}
|
|
2610
|
-
setStorage(getStorageKey("logout_processing"), "true");
|
|
2611
2495
|
try {
|
|
2612
2496
|
stopStorageWatcher();
|
|
2613
2497
|
stopCookieWatcher();
|
|
2614
|
-
const apiAuthBaseUrl = Config.
|
|
2498
|
+
const apiAuthBaseUrl = Config.getAuthServerUrl();
|
|
2615
2499
|
let serverLogoutSuccess = false;
|
|
2616
2500
|
let serverResponse;
|
|
2617
2501
|
if (apiAuthBaseUrl) {
|
|
@@ -2620,20 +2504,45 @@ async function logout(tenantKey) {
|
|
|
2620
2504
|
const logoutResult = await callServerLogout(logoutUrl);
|
|
2621
2505
|
serverLogoutSuccess = logoutResult.success;
|
|
2622
2506
|
serverResponse = logoutResult.response;
|
|
2507
|
+
if (!serverLogoutSuccess) {
|
|
2508
|
+
logger.warn("Server logout failed \u2013 session may still exist", {
|
|
2509
|
+
logoutUrl,
|
|
2510
|
+
serverResponse
|
|
2511
|
+
});
|
|
2512
|
+
}
|
|
2513
|
+
} else {
|
|
2514
|
+
logger.warn("API auth base URL not configured, performing local logout only");
|
|
2623
2515
|
}
|
|
2624
2516
|
performLocalLogoutCleanup();
|
|
2625
2517
|
const preservedTenantKey = getStorage(getStorageKey("preserved_tenant_key"));
|
|
2626
2518
|
if (preservedTenantKey) {
|
|
2627
|
-
|
|
2519
|
+
const propsKey = getStorageKey("props_config");
|
|
2520
|
+
let existing = {};
|
|
2521
|
+
try {
|
|
2522
|
+
const raw = getStorage(propsKey);
|
|
2523
|
+
if (raw) {
|
|
2524
|
+
existing = JSON.parse(raw);
|
|
2525
|
+
}
|
|
2526
|
+
} catch {
|
|
2527
|
+
existing = {};
|
|
2528
|
+
}
|
|
2529
|
+
const merged = {
|
|
2530
|
+
...existing,
|
|
2531
|
+
tenantKey: preservedTenantKey
|
|
2532
|
+
};
|
|
2533
|
+
setStorage(propsKey, JSON.stringify(merged));
|
|
2628
2534
|
removeStorage(getStorageKey("preserved_tenant_key"));
|
|
2629
2535
|
}
|
|
2630
2536
|
resetCookieWatcher();
|
|
2631
|
-
|
|
2537
|
+
startStorageWatcher();
|
|
2538
|
+
releaseLogoutLock();
|
|
2632
2539
|
logger.info("Logout completed \u2013 flags set, storage cleared, fresh login required", {
|
|
2633
2540
|
serverLogoutSuccess,
|
|
2634
2541
|
serverResponse
|
|
2635
2542
|
});
|
|
2636
2543
|
emitAuthEvent(AuthEventNames.LOGOUT_COMPLETED, {
|
|
2544
|
+
serverLogoutSuccess,
|
|
2545
|
+
tenantKey: getStorage(getStorageKey("preserved_tenant_key")) || void 0,
|
|
2637
2546
|
message: serverLogoutSuccess ? "Server logout success" : "Local logout only"
|
|
2638
2547
|
});
|
|
2639
2548
|
return {
|
|
@@ -2648,10 +2557,24 @@ async function logout(tenantKey) {
|
|
|
2648
2557
|
performLocalLogoutCleanup();
|
|
2649
2558
|
const preservedTenantKey = getStorage(getStorageKey("preserved_tenant_key"));
|
|
2650
2559
|
if (preservedTenantKey) {
|
|
2651
|
-
|
|
2560
|
+
const propsKey = getStorageKey("props_config");
|
|
2561
|
+
let existing = {};
|
|
2562
|
+
try {
|
|
2563
|
+
const raw = getStorage(propsKey);
|
|
2564
|
+
if (raw) {
|
|
2565
|
+
existing = JSON.parse(raw);
|
|
2566
|
+
}
|
|
2567
|
+
} catch {
|
|
2568
|
+
existing = {};
|
|
2569
|
+
}
|
|
2570
|
+
const merged = {
|
|
2571
|
+
...existing,
|
|
2572
|
+
tenantKey: preservedTenantKey
|
|
2573
|
+
};
|
|
2574
|
+
setStorage(propsKey, JSON.stringify(merged));
|
|
2652
2575
|
removeStorage(getStorageKey("preserved_tenant_key"));
|
|
2653
2576
|
}
|
|
2654
|
-
|
|
2577
|
+
releaseLogoutLock();
|
|
2655
2578
|
return {
|
|
2656
2579
|
success: true,
|
|
2657
2580
|
message: "Logged out locally due to an error. Fresh login required."
|
|
@@ -2671,16 +2594,16 @@ function useAuthContext() {
|
|
|
2671
2594
|
var ongoingRequests = /* @__PURE__ */ new Map();
|
|
2672
2595
|
var DEFAULT_SCOPES2 = OAUTH_CONSTANTS.SCOPES;
|
|
2673
2596
|
function getResolvedTenantBaseUrl() {
|
|
2674
|
-
let base = Config.
|
|
2597
|
+
let base = Config.getApiBaseUrl();
|
|
2675
2598
|
if (typeof window !== "undefined" && (!base || base.startsWith("/"))) {
|
|
2676
|
-
base = window.location.origin + (base || "
|
|
2599
|
+
base = window.location.origin + (base || "");
|
|
2677
2600
|
}
|
|
2678
2601
|
return base;
|
|
2679
2602
|
}
|
|
2680
2603
|
var PUBLIC_CODE_PREFIX = "public-";
|
|
2681
2604
|
function getTenantByCodeUrl(tenantCode) {
|
|
2682
2605
|
const apiTenantResolutionBaseUrl = getResolvedTenantBaseUrl();
|
|
2683
|
-
const base = apiTenantResolutionBaseUrl.replace(/\/api
|
|
2606
|
+
const base = (apiTenantResolutionBaseUrl || "").replace(/\/api(?:\/v1)?\/?$/, "") || apiTenantResolutionBaseUrl;
|
|
2684
2607
|
return `${base}/api/v1/tenant/public/tenants/by-code/${encodeURIComponent(tenantCode)}`;
|
|
2685
2608
|
}
|
|
2686
2609
|
async function resolveTenant(tenantKey) {
|
|
@@ -2716,7 +2639,9 @@ async function resolveTenant(tenantKey) {
|
|
|
2716
2639
|
if (!tenant.id || !tenant.clientCode) return null;
|
|
2717
2640
|
const authServer = Config.getAuthServerUrl();
|
|
2718
2641
|
const redirectUri = Config.getRedirectUri();
|
|
2719
|
-
if (!authServer || !redirectUri)
|
|
2642
|
+
if (!authServer || !redirectUri) {
|
|
2643
|
+
return null;
|
|
2644
|
+
}
|
|
2720
2645
|
const clientCodeWithPrefix = tenant.clientCode.startsWith(PUBLIC_CODE_PREFIX) ? tenant.clientCode : `${PUBLIC_CODE_PREFIX}${tenant.clientCode}`;
|
|
2721
2646
|
const config = {
|
|
2722
2647
|
tenantId: tenant.id,
|
|
@@ -2729,6 +2654,7 @@ async function resolveTenant(tenantKey) {
|
|
|
2729
2654
|
scopes: DEFAULT_SCOPES2
|
|
2730
2655
|
}
|
|
2731
2656
|
};
|
|
2657
|
+
console.log("config====", config);
|
|
2732
2658
|
logger.debug("Resolved tenant config", { tenantCode });
|
|
2733
2659
|
return config;
|
|
2734
2660
|
} catch (error) {
|
|
@@ -2790,13 +2716,10 @@ function createBrowserUrlProvider() {
|
|
|
2790
2716
|
}
|
|
2791
2717
|
function createConfigProvider() {
|
|
2792
2718
|
return {
|
|
2793
|
-
getApiBaseUrl: () => Config.
|
|
2719
|
+
getApiBaseUrl: () => Config.getApiBaseUrl(),
|
|
2794
2720
|
getAuthServerUrl: () => Config.getAuthServerUrl(),
|
|
2795
2721
|
getRedirectUri: () => Config.getRedirectUri(),
|
|
2796
|
-
|
|
2797
|
-
getTenantId: () => Config.getTenantId(),
|
|
2798
|
-
getClientCode: () => Config.getClientCode(),
|
|
2799
|
-
getBasePath: () => Config.getBasePath()
|
|
2722
|
+
getClientCode: () => Config.getClientCode()
|
|
2800
2723
|
};
|
|
2801
2724
|
}
|
|
2802
2725
|
function createTenantResolver() {
|
|
@@ -2960,6 +2883,9 @@ function AuthProvider({
|
|
|
2960
2883
|
children,
|
|
2961
2884
|
autoInit = true,
|
|
2962
2885
|
tenantCode,
|
|
2886
|
+
apiBaseUrl,
|
|
2887
|
+
authServerUrl,
|
|
2888
|
+
callbackUrl,
|
|
2963
2889
|
appId = "",
|
|
2964
2890
|
storageAdapter
|
|
2965
2891
|
}) {
|
|
@@ -2971,13 +2897,40 @@ function AuthProvider({
|
|
|
2971
2897
|
const initRanRef = react.useRef(false);
|
|
2972
2898
|
const engineRef = react.useRef(null);
|
|
2973
2899
|
react.useLayoutEffect(() => {
|
|
2974
|
-
|
|
2975
|
-
|
|
2900
|
+
logger.debug("[AuthProvider] Host config props", {
|
|
2901
|
+
tenantCode: tenantCode ?? "(not provided)",
|
|
2902
|
+
apiBaseUrl: apiBaseUrl ? apiBaseUrl : "(empty)",
|
|
2903
|
+
authServerUrl: authServerUrl ? authServerUrl : "(empty)",
|
|
2904
|
+
callbackUrl: callbackUrl ? callbackUrl : "(empty)"
|
|
2905
|
+
});
|
|
2906
|
+
if (!authServerUrl || !authServerUrl.trim()) {
|
|
2907
|
+
logger.warn("[AuthProvider] authServerUrl missing from host props");
|
|
2908
|
+
}
|
|
2909
|
+
if (!callbackUrl || !callbackUrl.trim()) {
|
|
2910
|
+
logger.warn("[AuthProvider] callbackUrl missing from host props");
|
|
2976
2911
|
}
|
|
2912
|
+
setConfig({
|
|
2913
|
+
...tenantCode ? { tenantCode } : {},
|
|
2914
|
+
...apiBaseUrl ? { apiBaseUrl } : {},
|
|
2915
|
+
...authServerUrl ? { authServerUrl } : {},
|
|
2916
|
+
...callbackUrl ? { callbackUrl } : {}
|
|
2917
|
+
});
|
|
2977
2918
|
return () => {
|
|
2978
2919
|
clearConfigOverrides();
|
|
2979
2920
|
};
|
|
2980
|
-
}, [tenantCode]);
|
|
2921
|
+
}, [tenantCode, apiBaseUrl, authServerUrl, callbackUrl]);
|
|
2922
|
+
react.useEffect(() => {
|
|
2923
|
+
try {
|
|
2924
|
+
const payload = {
|
|
2925
|
+
tenantCode: tenantCode ?? "",
|
|
2926
|
+
apiBaseUrl: apiBaseUrl ?? "",
|
|
2927
|
+
authServerUrl: authServerUrl ?? "",
|
|
2928
|
+
callbackUrl: callbackUrl ?? ""
|
|
2929
|
+
};
|
|
2930
|
+
setStorage(getStorageKey("host_config"), JSON.stringify(payload));
|
|
2931
|
+
} catch {
|
|
2932
|
+
}
|
|
2933
|
+
}, [tenantCode, apiBaseUrl, authServerUrl, callbackUrl]);
|
|
2981
2934
|
react.useLayoutEffect(() => {
|
|
2982
2935
|
setStorageKeyPrefix(resolvedTenantKey ?? "");
|
|
2983
2936
|
const adapter = storageAdapter !== void 0 && storageAdapter !== null ? storageAdapter : createSecureSessionStorageAdapter(namespace);
|
|
@@ -3461,11 +3414,9 @@ exports.extractTenantKey = extractTenantKey;
|
|
|
3461
3414
|
exports.getAccessToken = getAccessToken2;
|
|
3462
3415
|
exports.getAuthRuntime = getAuthRuntime;
|
|
3463
3416
|
exports.getConfig = getConfig;
|
|
3464
|
-
exports.getEnvConfig = getEnvConfig;
|
|
3465
3417
|
exports.getStorageAdapter = getStorageAdapter;
|
|
3466
3418
|
exports.getStorageNamespace = getStorageNamespace;
|
|
3467
3419
|
exports.getStoredAccessToken = getAccessToken;
|
|
3468
|
-
exports.hasEnvFallback = hasEnvFallback;
|
|
3469
3420
|
exports.isAccessTokenExpired = isAccessTokenExpired;
|
|
3470
3421
|
exports.isCallbackUrl = isCallbackUrl;
|
|
3471
3422
|
exports.logout = logout;
|