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.mjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
1
|
import axios from 'axios';
|
|
3
2
|
import { createContext, useContext, useMemo, useRef, useLayoutEffect, useEffect, useState, useCallback } from 'react';
|
|
4
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -67,13 +66,11 @@ function extractTenantKeyFromUrl(url, config, getStorage3, getKey) {
|
|
|
67
66
|
if (keyFromHost) return keyFromHost;
|
|
68
67
|
const clientCode = config.getClientCode();
|
|
69
68
|
if (clientCode?.trim()) return clientCode.trim();
|
|
70
|
-
const tenantId = config.getTenantId();
|
|
71
|
-
if (tenantId?.trim()) return tenantId.trim();
|
|
72
69
|
return config.getClientCode();
|
|
73
70
|
} catch {
|
|
74
71
|
const clientCode = config.getClientCode();
|
|
75
72
|
if (clientCode?.trim()) return clientCode.trim();
|
|
76
|
-
return config.
|
|
73
|
+
return config.getClientCode();
|
|
77
74
|
}
|
|
78
75
|
}
|
|
79
76
|
function isCallbackUrlFromUrl(url) {
|
|
@@ -804,85 +801,6 @@ function generateState() {
|
|
|
804
801
|
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
805
802
|
}
|
|
806
803
|
|
|
807
|
-
// src/config/env.ts
|
|
808
|
-
var ENV_KEYS = {
|
|
809
|
-
CLIENT_ID: ["VITE_CLIENT_ID", "CLIENT_ID"],
|
|
810
|
-
TENANT_ID: ["VITE_TENANT_ID", "TENANT_ID"],
|
|
811
|
-
CLIENTCODE: ["VITE_CLIENTCODE", "CLIENTCODE"]
|
|
812
|
-
};
|
|
813
|
-
function getEnvValue(keys) {
|
|
814
|
-
try {
|
|
815
|
-
const g = typeof globalThis !== "undefined" ? globalThis : null;
|
|
816
|
-
const env = g?.process && typeof g.process.env === "object" ? g.process.env : null;
|
|
817
|
-
if (env) {
|
|
818
|
-
for (const key of keys) {
|
|
819
|
-
const v = env[key];
|
|
820
|
-
if (v != null && String(v).trim()) return String(v).trim();
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
} catch {
|
|
824
|
-
}
|
|
825
|
-
try {
|
|
826
|
-
const meta = typeof import.meta !== "undefined" ? import.meta.env : void 0;
|
|
827
|
-
if (meta) {
|
|
828
|
-
for (const key of keys) {
|
|
829
|
-
const v = meta[key];
|
|
830
|
-
if (v != null && String(v).trim()) return String(v).trim();
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
} catch {
|
|
834
|
-
}
|
|
835
|
-
return "";
|
|
836
|
-
}
|
|
837
|
-
var FORBIDDEN_WINDOW_KEYS = ["apiBaseUrl", "apiTenantResolutionBaseUrl", "apiAuthBaseUrl", "authServerUrl", "defaultDomain", "API_BASE_URL", "AUTH_SERVER_URL", "DEFAULT_DOMAIN"];
|
|
838
|
-
function getWindowConfigRaw() {
|
|
839
|
-
if (typeof window === "undefined") return null;
|
|
840
|
-
const w = window;
|
|
841
|
-
const raw = w.__AUTH_CONFIG__ ?? w.__APP_CONFIG__;
|
|
842
|
-
if (!raw || typeof raw !== "object") return null;
|
|
843
|
-
for (const forbidden of FORBIDDEN_WINDOW_KEYS) {
|
|
844
|
-
if (forbidden in raw) {
|
|
845
|
-
throw new Error("Attempted to override protected internal configuration");
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
const out = {};
|
|
849
|
-
const map = {
|
|
850
|
-
clientId: "CLIENT_ID",
|
|
851
|
-
tenantId: "TENANT_ID",
|
|
852
|
-
clientcode: "CLIENTCODE"
|
|
853
|
-
};
|
|
854
|
-
for (const [winKey, sdkKey] of Object.entries(map)) {
|
|
855
|
-
const v = raw[winKey];
|
|
856
|
-
if (v != null && typeof v === "string" && v.trim()) out[sdkKey] = v.trim();
|
|
857
|
-
}
|
|
858
|
-
return Object.keys(out).length ? out : null;
|
|
859
|
-
}
|
|
860
|
-
function loadEnvConfig() {
|
|
861
|
-
const partial = {};
|
|
862
|
-
for (const [key, envKeys] of Object.entries(ENV_KEYS)) {
|
|
863
|
-
const v = getEnvValue(envKeys);
|
|
864
|
-
if (v) partial[key] = v;
|
|
865
|
-
}
|
|
866
|
-
return partial;
|
|
867
|
-
}
|
|
868
|
-
function loadWindowConfig() {
|
|
869
|
-
const raw = getWindowConfigRaw();
|
|
870
|
-
if (!raw) return null;
|
|
871
|
-
return raw;
|
|
872
|
-
}
|
|
873
|
-
var schema = z.object({
|
|
874
|
-
CLIENT_ID: z.string().min(1, "CLIENT_ID is required"),
|
|
875
|
-
TENANT_ID: z.string().min(1, "TENANT_ID is required"),
|
|
876
|
-
CLIENTCODE: z.string().min(1, "CLIENTCODE is required")
|
|
877
|
-
});
|
|
878
|
-
function validateConfig(data) {
|
|
879
|
-
return schema.parse(data);
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
// src/config/types.ts
|
|
883
|
-
var INTERNAL_CONFIG_KEYS = ["API_TENANT_RESOLUTION_BASE_URL", "API_AUTH_BASE_URL", "AUTH_SERVER_URL", "DEFAULT_DOMAIN"];
|
|
884
|
-
var RUNTIME_CONFIG_KEYS = ["CLIENT_ID", "TENANT_ID", "CLIENTCODE"];
|
|
885
|
-
|
|
886
804
|
// src/config/constants.ts
|
|
887
805
|
var OAUTH_CONSTANTS = {
|
|
888
806
|
SCOPES: "openid profile email",
|
|
@@ -910,232 +828,63 @@ var DEFAULT_TOKEN_GRANT_TYPE = OAUTH_CONSTANTS.TOKEN_GRANT_TYPE;
|
|
|
910
828
|
var DEFAULT_REFRESH_GRANT_TYPE = OAUTH_CONSTANTS.REFRESH_GRANT_TYPE;
|
|
911
829
|
|
|
912
830
|
// src/config/index.ts
|
|
913
|
-
var
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
}
|
|
934
|
-
function pickRuntimeConfig(source) {
|
|
935
|
-
if (!source) return {};
|
|
936
|
-
const picked = {};
|
|
937
|
-
for (const key of RUNTIME_CONFIG_KEYS) {
|
|
938
|
-
const value = source[key];
|
|
939
|
-
if (value != null && typeof value === "string") {
|
|
940
|
-
const trimmed = value.trim();
|
|
941
|
-
if (trimmed) picked[key] = trimmed;
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
return picked;
|
|
945
|
-
}
|
|
946
|
-
({
|
|
947
|
-
...INTERNAL_CONFIG,
|
|
948
|
-
...RUNTIME_CONFIG_DEFAULTS
|
|
949
|
-
});
|
|
950
|
-
var runtimeOverrides = {};
|
|
951
|
-
var runtimeConfigOverrides = {};
|
|
952
|
-
function mergeRuntime(base, ...sources) {
|
|
953
|
-
let out = { ...base };
|
|
954
|
-
for (const src of sources) {
|
|
955
|
-
if (!src) continue;
|
|
956
|
-
for (const key of Object.keys(src)) {
|
|
957
|
-
const value = src[key];
|
|
958
|
-
if (value != null && String(value).trim() !== "") out[key] = String(value).trim();
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
return out;
|
|
962
|
-
}
|
|
963
|
-
function assertNoInternalOverrides(source) {
|
|
964
|
-
if (!source) return;
|
|
965
|
-
for (const key of INTERNAL_CONFIG_KEYS) {
|
|
966
|
-
if (source[key] !== void 0) throw new Error("Attempted to override protected internal configuration");
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
var INTERNAL_KEY_SET = new Set(INTERNAL_CONFIG_KEYS);
|
|
970
|
-
var HOST_TO_RUNTIME_KEYS = {
|
|
971
|
-
clientId: "CLIENT_ID",
|
|
972
|
-
tenantId: "TENANT_ID",
|
|
973
|
-
clientcode: "CLIENTCODE"
|
|
974
|
-
};
|
|
975
|
-
function sanitizeRuntimeOverrides(source) {
|
|
976
|
-
if (!source) return void 0;
|
|
977
|
-
const filtered = {};
|
|
978
|
-
for (const [key, raw] of Object.entries(source)) {
|
|
979
|
-
if (raw == null) continue;
|
|
980
|
-
if (INTERNAL_KEY_SET.has(key)) continue;
|
|
981
|
-
const trimmed = String(raw).trim();
|
|
982
|
-
if (!trimmed) continue;
|
|
983
|
-
const sdkKey = HOST_TO_RUNTIME_KEYS[key] ?? key;
|
|
984
|
-
filtered[sdkKey] = trimmed;
|
|
985
|
-
}
|
|
986
|
-
const picked = pickRuntimeConfig(filtered);
|
|
987
|
-
return Object.keys(picked).length ? picked : void 0;
|
|
831
|
+
var inMemoryConfig = {};
|
|
832
|
+
function readHostConfigFromStorage() {
|
|
833
|
+
try {
|
|
834
|
+
const raw = getStorage(getStorageKey("host_config"));
|
|
835
|
+
if (!raw) return {};
|
|
836
|
+
const parsed = JSON.parse(raw);
|
|
837
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
838
|
+
} catch {
|
|
839
|
+
return {};
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
function resolveMerged(overrides) {
|
|
843
|
+
const stored = readHostConfigFromStorage();
|
|
844
|
+
const cfg = { ...stored, ...inMemoryConfig, ...overrides ?? {} };
|
|
845
|
+
const trimmed = (v) => v == null ? "" : String(v).trim();
|
|
846
|
+
return {
|
|
847
|
+
apiBaseUrl: trimmed(cfg.apiBaseUrl),
|
|
848
|
+
authServerUrl: trimmed(cfg.authServerUrl),
|
|
849
|
+
callbackUrl: trimmed(cfg.callbackUrl),
|
|
850
|
+
clientCode: trimmed(cfg.clientCode)
|
|
851
|
+
};
|
|
988
852
|
}
|
|
989
853
|
function resolveConfig(overrides) {
|
|
990
|
-
|
|
991
|
-
assertNoInternalOverrides(overrides);
|
|
992
|
-
const windowCfg = loadWindowConfig();
|
|
993
|
-
const envCfg = loadEnvConfig();
|
|
994
|
-
const mergedRuntime = mergeRuntime(
|
|
995
|
-
RUNTIME_CONFIG_DEFAULTS,
|
|
996
|
-
envCfg,
|
|
997
|
-
windowCfg ?? void 0,
|
|
998
|
-
runtimeOverrides,
|
|
999
|
-
sanitizeRuntimeOverrides(overrides)
|
|
1000
|
-
);
|
|
1001
|
-
const validatedRuntime = validateConfig(mergedRuntime);
|
|
1002
|
-
return { ...INTERNAL_CONFIG, ...validatedRuntime };
|
|
854
|
+
return resolveMerged(overrides);
|
|
1003
855
|
}
|
|
1004
856
|
function getConfig() {
|
|
1005
|
-
return
|
|
857
|
+
return resolveMerged();
|
|
1006
858
|
}
|
|
1007
859
|
function setConfig(overrides) {
|
|
1008
|
-
|
|
1009
|
-
const sanitized = sanitizeRuntimeOverrides(overrides);
|
|
1010
|
-
if (sanitized) runtimeOverrides = { ...runtimeOverrides, ...sanitized };
|
|
1011
|
-
const { basePath, redirectUri } = overrides;
|
|
1012
|
-
if (basePath != null && basePath.trim() !== "") runtimeConfigOverrides = { ...runtimeConfigOverrides, basePath: basePath.trim() };
|
|
1013
|
-
if (redirectUri != null && redirectUri.trim() !== "") runtimeConfigOverrides = { ...runtimeConfigOverrides, redirectUri: redirectUri.trim() };
|
|
860
|
+
inMemoryConfig = { ...inMemoryConfig, ...overrides };
|
|
1014
861
|
}
|
|
1015
862
|
function clearConfigOverrides() {
|
|
1016
|
-
|
|
1017
|
-
runtimeConfigOverrides = {};
|
|
1018
|
-
}
|
|
1019
|
-
function getWindowBasePath() {
|
|
1020
|
-
if (typeof window === "undefined") return "";
|
|
1021
|
-
const w = window;
|
|
1022
|
-
const raw = w.__AUTH_CONFIG__ ?? w.__APP_CONFIG__;
|
|
1023
|
-
const bp = raw?.basePath;
|
|
1024
|
-
if (bp != null && typeof bp === "string" && bp.trim()) return bp.trim();
|
|
1025
|
-
const pathname = window.location.pathname;
|
|
1026
|
-
const segments = pathname.split("/").filter(Boolean);
|
|
1027
|
-
const commonRoutes = ["dashboards", "callback", "confirmation", "client-confirmed", "client-provisioned", "approval-completed"];
|
|
1028
|
-
if (segments.length > 0 && !commonRoutes.includes(segments[0])) {
|
|
1029
|
-
let base = "/" + segments[0];
|
|
1030
|
-
if (base.endsWith("/")) base = base.slice(0, -1);
|
|
1031
|
-
return base;
|
|
1032
|
-
}
|
|
1033
|
-
return "";
|
|
1034
|
-
}
|
|
1035
|
-
function getBasePath() {
|
|
1036
|
-
if (runtimeConfigOverrides.basePath != null && runtimeConfigOverrides.basePath !== "") return runtimeConfigOverrides.basePath;
|
|
1037
|
-
return getWindowBasePath();
|
|
863
|
+
inMemoryConfig = {};
|
|
1038
864
|
}
|
|
1039
865
|
function getRedirectUri2() {
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
}
|
|
1043
|
-
return
|
|
1044
|
-
}
|
|
1045
|
-
function hasRuntimeConfig() {
|
|
1046
|
-
return loadWindowConfig() !== null || Object.keys(runtimeOverrides).length > 0;
|
|
866
|
+
const cfg = resolveMerged();
|
|
867
|
+
if (cfg.callbackUrl) return cfg.callbackUrl;
|
|
868
|
+
if (typeof window !== "undefined") return `${window.location.origin}/callback`;
|
|
869
|
+
return "";
|
|
1047
870
|
}
|
|
1048
871
|
var Config = {
|
|
1049
|
-
|
|
1050
|
-
return
|
|
1051
|
-
},
|
|
1052
|
-
getApiAuthBaseUrl() {
|
|
1053
|
-
return getConfig().API_AUTH_BASE_URL;
|
|
872
|
+
getApiBaseUrl() {
|
|
873
|
+
return resolveMerged().apiBaseUrl;
|
|
1054
874
|
},
|
|
1055
875
|
getAuthServerUrl() {
|
|
1056
|
-
return
|
|
1057
|
-
},
|
|
1058
|
-
getDefaultDomain() {
|
|
1059
|
-
return getConfig().DEFAULT_DOMAIN;
|
|
1060
|
-
},
|
|
1061
|
-
getClientId() {
|
|
1062
|
-
return getConfig().CLIENT_ID;
|
|
1063
|
-
},
|
|
1064
|
-
getTenantId() {
|
|
1065
|
-
return getConfig().TENANT_ID;
|
|
876
|
+
return resolveMerged().authServerUrl;
|
|
1066
877
|
},
|
|
1067
878
|
getClientCode() {
|
|
1068
|
-
return
|
|
879
|
+
return resolveMerged().clientCode;
|
|
1069
880
|
},
|
|
1070
881
|
getRedirectUri() {
|
|
1071
882
|
return getRedirectUri2();
|
|
1072
883
|
},
|
|
1073
|
-
getBasePath() {
|
|
1074
|
-
return getBasePath();
|
|
1075
|
-
},
|
|
1076
|
-
hasRuntimeConfig() {
|
|
1077
|
-
return hasRuntimeConfig();
|
|
1078
|
-
},
|
|
1079
884
|
getAll() {
|
|
1080
|
-
|
|
1081
|
-
return {
|
|
1082
|
-
apiTenantResolutionBaseUrl: c.API_TENANT_RESOLUTION_BASE_URL,
|
|
1083
|
-
apiAuthBaseUrl: c.API_AUTH_BASE_URL,
|
|
1084
|
-
authServerUrl: c.AUTH_SERVER_URL,
|
|
1085
|
-
defaultDomain: c.DEFAULT_DOMAIN,
|
|
1086
|
-
clientId: c.CLIENT_ID,
|
|
1087
|
-
tenantId: c.TENANT_ID,
|
|
1088
|
-
clientCode: c.CLIENTCODE,
|
|
1089
|
-
redirectUri: getRedirectUri2(),
|
|
1090
|
-
basePath: getBasePath()
|
|
1091
|
-
};
|
|
885
|
+
return resolveMerged();
|
|
1092
886
|
}
|
|
1093
887
|
};
|
|
1094
|
-
({
|
|
1095
|
-
AUTH_SERVER_URL: Config.getAuthServerUrl(),
|
|
1096
|
-
CLIENT_ID: Config.getClientId(),
|
|
1097
|
-
TENANT_ID: Config.getTenantId(),
|
|
1098
|
-
CLIENTCODE: Config.getClientCode()
|
|
1099
|
-
});
|
|
1100
|
-
function getEnvConfig() {
|
|
1101
|
-
const authServerUrl = Config.getAuthServerUrl();
|
|
1102
|
-
const clientId = Config.getClientId();
|
|
1103
|
-
const tenantId = Config.getTenantId();
|
|
1104
|
-
const redirectUri = Config.getRedirectUri();
|
|
1105
|
-
try {
|
|
1106
|
-
new URL(authServerUrl);
|
|
1107
|
-
new URL(redirectUri);
|
|
1108
|
-
} catch {
|
|
1109
|
-
return Promise.resolve(null);
|
|
1110
|
-
}
|
|
1111
|
-
return Promise.resolve({
|
|
1112
|
-
authServerUrl: authServerUrl.trim(),
|
|
1113
|
-
clientId: clientId.trim(),
|
|
1114
|
-
redirectUri: redirectUri.trim(),
|
|
1115
|
-
tenantId: tenantId.trim()
|
|
1116
|
-
});
|
|
1117
|
-
}
|
|
1118
|
-
function getEnvConfigSync() {
|
|
1119
|
-
const authServerUrl = Config.getAuthServerUrl();
|
|
1120
|
-
const clientId = Config.getClientId();
|
|
1121
|
-
const tenantId = Config.getTenantId();
|
|
1122
|
-
const redirectUri = Config.getRedirectUri();
|
|
1123
|
-
try {
|
|
1124
|
-
new URL(authServerUrl);
|
|
1125
|
-
new URL(redirectUri);
|
|
1126
|
-
} catch {
|
|
1127
|
-
return null;
|
|
1128
|
-
}
|
|
1129
|
-
return {
|
|
1130
|
-
authServerUrl: authServerUrl.trim(),
|
|
1131
|
-
clientId: clientId.trim(),
|
|
1132
|
-
redirectUri: redirectUri.trim(),
|
|
1133
|
-
tenantId: tenantId.trim()
|
|
1134
|
-
};
|
|
1135
|
-
}
|
|
1136
|
-
function hasEnvFallback() {
|
|
1137
|
-
return getEnvConfigSync() !== null;
|
|
1138
|
-
}
|
|
1139
888
|
|
|
1140
889
|
// src/utils/validation.ts
|
|
1141
890
|
function isValidGuid(guid) {
|
|
@@ -1289,7 +1038,8 @@ function storeTenantConfig(config) {
|
|
|
1289
1038
|
if (!validation.isValid) {
|
|
1290
1039
|
logger.warn("Tenant ID validation failed", { tenantId: config.tenantId });
|
|
1291
1040
|
}
|
|
1292
|
-
|
|
1041
|
+
const authServerToStore = Config.getAuthServerUrl() || config.authServer;
|
|
1042
|
+
setStorage(STORAGE_KEYS.authServerUrl, authServerToStore);
|
|
1293
1043
|
setStorage(STORAGE_KEYS.clientId, config.client.clientId);
|
|
1294
1044
|
setStorage(STORAGE_KEYS.redirectUri, Config.getRedirectUri());
|
|
1295
1045
|
setStorage(STORAGE_KEYS.tenantId, config.tenantId);
|
|
@@ -1300,6 +1050,22 @@ function storeTenantConfig(config) {
|
|
|
1300
1050
|
async function initiateAuthFlow(config) {
|
|
1301
1051
|
try {
|
|
1302
1052
|
logger.info("Initiating OAuth authorization flow");
|
|
1053
|
+
const authServerFromProps = Config.getAuthServerUrl();
|
|
1054
|
+
const authServerEffective = (authServerFromProps || config?.authServer || "").replace(/\/+$/, "");
|
|
1055
|
+
const redirectUriEffective = Config.getRedirectUri();
|
|
1056
|
+
const storedTenantId = getStorage(STORAGE_KEYS.tenantId);
|
|
1057
|
+
const storedClientId = getStorage(STORAGE_KEYS.clientId);
|
|
1058
|
+
const tenantIdEffective = storedTenantId || config?.tenantId || "";
|
|
1059
|
+
const clientIdEffective = storedClientId || config?.client?.clientId || "";
|
|
1060
|
+
logger.debug("[initiateAuthFlow] Resolved inputs", {
|
|
1061
|
+
authServerFromProps: authServerFromProps ? "(provided)" : "(empty)",
|
|
1062
|
+
authServerEffective,
|
|
1063
|
+
redirectUriEffective,
|
|
1064
|
+
tenantIdEffective,
|
|
1065
|
+
clientIdEffective,
|
|
1066
|
+
scopes: config?.client?.scopes,
|
|
1067
|
+
hasRuntime: !!getAuthRuntime()
|
|
1068
|
+
});
|
|
1303
1069
|
const token = getAccessToken();
|
|
1304
1070
|
if (token && !isAccessTokenExpired()) {
|
|
1305
1071
|
logger.debug("Valid token already exists, skipping auth flow");
|
|
@@ -1321,10 +1087,17 @@ async function initiateAuthFlow(config) {
|
|
|
1321
1087
|
}
|
|
1322
1088
|
}
|
|
1323
1089
|
setFlowFlags();
|
|
1324
|
-
if (!config?.authServer || !config.client?.clientId || !config.client?.redirectUri) {
|
|
1090
|
+
if (!(Config.getAuthServerUrl() || config?.authServer) || !config.client?.clientId || !config.client?.redirectUri) {
|
|
1091
|
+
logger.error("[initiateAuthFlow] Missing required tenant config", {
|
|
1092
|
+
authServerEffective,
|
|
1093
|
+
clientId: config?.client?.clientId,
|
|
1094
|
+
redirectUriFromTenantApi: config?.client?.redirectUri,
|
|
1095
|
+
redirectUriEffective
|
|
1096
|
+
});
|
|
1325
1097
|
throw new Error("Invalid tenant configuration for auth flow");
|
|
1326
1098
|
}
|
|
1327
1099
|
storeTenantConfig(config);
|
|
1100
|
+
logger.debug("[initiateAuthFlow] Stored tenant config, generating PKCE");
|
|
1328
1101
|
const codeVerifier = generateCodeVerifier();
|
|
1329
1102
|
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
|
1330
1103
|
const state = generateState();
|
|
@@ -1333,6 +1106,10 @@ async function initiateAuthFlow(config) {
|
|
|
1333
1106
|
setStorage(STORAGE_KEYS.codeVerifier, codeVerifier);
|
|
1334
1107
|
setStorage(STORAGE_KEYS.state, state);
|
|
1335
1108
|
const authUrl = buildAuthorizationUrl(config, codeChallenge, state);
|
|
1109
|
+
logger.debug("[initiateAuthFlow] Built authorization URL", {
|
|
1110
|
+
authServerEffective,
|
|
1111
|
+
urlPrefix: authUrl?.slice(0, 80)
|
|
1112
|
+
});
|
|
1336
1113
|
if (!authUrl || !(authUrl.startsWith("http://") || authUrl.startsWith("https://"))) {
|
|
1337
1114
|
throw new Error("Invalid authorization URL generated");
|
|
1338
1115
|
}
|
|
@@ -1344,8 +1121,15 @@ async function initiateAuthFlow(config) {
|
|
|
1344
1121
|
logger.info("Redirecting to authorization server");
|
|
1345
1122
|
emitAuthEvent(AuthEventNames.LOGIN_STARTED, { tenantKey: config.tenantKey });
|
|
1346
1123
|
const runtime = getAuthRuntime();
|
|
1347
|
-
if (runtime)
|
|
1348
|
-
|
|
1124
|
+
if (runtime) {
|
|
1125
|
+
logger.debug("[initiateAuthFlow] Redirect via runtime.urlProvider.redirect");
|
|
1126
|
+
runtime.urlProvider.redirect(authUrl);
|
|
1127
|
+
} else if (typeof window !== "undefined") {
|
|
1128
|
+
logger.debug("[initiateAuthFlow] Redirect via window.location.replace");
|
|
1129
|
+
window.location.replace(authUrl);
|
|
1130
|
+
} else {
|
|
1131
|
+
logger.error("[initiateAuthFlow] No runtime and no window; cannot redirect", { authUrl });
|
|
1132
|
+
}
|
|
1349
1133
|
} catch (error) {
|
|
1350
1134
|
clearFlowFlags();
|
|
1351
1135
|
logger.error("Failed to initiate auth flow", {
|
|
@@ -1355,9 +1139,10 @@ async function initiateAuthFlow(config) {
|
|
|
1355
1139
|
}
|
|
1356
1140
|
}
|
|
1357
1141
|
function buildAuthorizationUrl(config, codeChallenge, state) {
|
|
1142
|
+
const authServerBase = (Config.getAuthServerUrl() || config.authServer || "").replace(/\/+$/, "");
|
|
1358
1143
|
if (isLocalhost2()) {
|
|
1359
1144
|
logger.debug("Building authorization URL", {
|
|
1360
|
-
authServer:
|
|
1145
|
+
authServer: authServerBase,
|
|
1361
1146
|
clientId: config.client.clientId,
|
|
1362
1147
|
redirectUri: config.client.redirectUri,
|
|
1363
1148
|
scopes: config.client.scopes
|
|
@@ -1378,7 +1163,7 @@ function buildAuthorizationUrl(config, codeChallenge, state) {
|
|
|
1378
1163
|
code_challenge: codeChallenge,
|
|
1379
1164
|
code_challenge_method: DEFAULT_CODE_CHALLENGE_METHOD
|
|
1380
1165
|
});
|
|
1381
|
-
return `${
|
|
1166
|
+
return `${authServerBase}/connect/authorize?${params.toString()}`;
|
|
1382
1167
|
}
|
|
1383
1168
|
|
|
1384
1169
|
// src/strategies/oauth2-pkce/token-exchange.ts
|
|
@@ -1408,7 +1193,7 @@ function storeTokens(tokenData) {
|
|
|
1408
1193
|
async function exchangeCodeForTokens(params) {
|
|
1409
1194
|
try {
|
|
1410
1195
|
const { code, codeVerifier, clientId, redirectUri } = params;
|
|
1411
|
-
const apiAuthBaseUrl = Config.
|
|
1196
|
+
const apiAuthBaseUrl = Config.getAuthServerUrl();
|
|
1412
1197
|
const tokenUrl = `${apiAuthBaseUrl}/oauth/token`;
|
|
1413
1198
|
const body = new URLSearchParams({
|
|
1414
1199
|
grant_type: DEFAULT_TOKEN_GRANT_TYPE,
|
|
@@ -1482,7 +1267,7 @@ async function refreshAccessToken() {
|
|
|
1482
1267
|
});
|
|
1483
1268
|
throw new Error("Cannot refresh token: missing required data");
|
|
1484
1269
|
}
|
|
1485
|
-
const apiAuthBaseUrl = Config.
|
|
1270
|
+
const apiAuthBaseUrl = Config.getApiBaseUrl();
|
|
1486
1271
|
const tokenUrl = `${apiAuthBaseUrl}/oauth/refresh`;
|
|
1487
1272
|
const body = new URLSearchParams({
|
|
1488
1273
|
grant_type: DEFAULT_REFRESH_GRANT_TYPE,
|
|
@@ -1879,40 +1664,15 @@ function mergeConfigWithProps(apiEnvConfig, propsConfig, tenantKey) {
|
|
|
1879
1664
|
}
|
|
1880
1665
|
};
|
|
1881
1666
|
}
|
|
1882
|
-
async function buildTenantConfigFromEnv() {
|
|
1883
|
-
const envConfig = await getEnvConfig();
|
|
1884
|
-
if (!envConfig) return null;
|
|
1885
|
-
return {
|
|
1886
|
-
tenantId: envConfig.tenantId,
|
|
1887
|
-
authServer: envConfig.authServerUrl,
|
|
1888
|
-
client: {
|
|
1889
|
-
clientId: envConfig.clientId,
|
|
1890
|
-
redirectUri: envConfig.redirectUri,
|
|
1891
|
-
scopes: "openid profile email"
|
|
1892
|
-
}
|
|
1893
|
-
};
|
|
1894
|
-
}
|
|
1895
1667
|
async function resolveTenantConfig(tenantKey, tenantResolver) {
|
|
1896
1668
|
if (!tenantKey) return null;
|
|
1897
1669
|
const propsConfig = getPropsConfig();
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
apiEnvConfig = await tenantResolver.resolve(tenantKey);
|
|
1901
|
-
apiResolved = !!apiEnvConfig;
|
|
1902
|
-
if (!apiEnvConfig) {
|
|
1903
|
-
apiEnvConfig = await buildTenantConfigFromEnv();
|
|
1904
|
-
}
|
|
1905
|
-
if (!apiEnvConfig) return null;
|
|
1906
|
-
if (!apiResolved && propsConfig) {
|
|
1907
|
-
const mergedConfig = mergeConfigWithProps(apiEnvConfig, propsConfig, tenantKey);
|
|
1908
|
-
removeStorage(getStorageKey("props_config"));
|
|
1909
|
-
logger.info("Merged props config with ENV fallback config");
|
|
1910
|
-
return mergedConfig;
|
|
1911
|
-
}
|
|
1670
|
+
const resolved = await tenantResolver.resolve(tenantKey);
|
|
1671
|
+
if (!resolved) return null;
|
|
1912
1672
|
removeStorage(getStorageKey("props_config"));
|
|
1913
1673
|
return {
|
|
1914
|
-
...
|
|
1915
|
-
tenantKey: tenantKey ||
|
|
1674
|
+
...propsConfig ? mergeConfigWithProps(resolved, propsConfig, tenantKey) : resolved,
|
|
1675
|
+
tenantKey: tenantKey || resolved.tenantKey
|
|
1916
1676
|
};
|
|
1917
1677
|
}
|
|
1918
1678
|
async function resolveTenantConfigCached(tenantKey, tenantResolver) {
|
|
@@ -2106,6 +1866,8 @@ var LoginFlow = class {
|
|
|
2106
1866
|
const { runtime } = context;
|
|
2107
1867
|
const { logger: log } = runtime;
|
|
2108
1868
|
const getUrl = () => runtime.urlProvider.getCurrentUrl();
|
|
1869
|
+
const url = getUrl();
|
|
1870
|
+
log.debug("[LoginFlow] Start", { url: url.href, pathname: url.pathname, search: url.search });
|
|
2109
1871
|
const callbackProcessed = getStorage(getStorageKey("callback_processed")) === "true";
|
|
2110
1872
|
const token = getAccessToken();
|
|
2111
1873
|
if (callbackProcessed && !token) {
|
|
@@ -2115,7 +1877,8 @@ var LoginFlow = class {
|
|
|
2115
1877
|
}
|
|
2116
1878
|
const wasStateMismatch = getStorage(getStorageKey("state_mismatch")) === "true";
|
|
2117
1879
|
if (wasStateMismatch) removeStorage(getStorageKey("state_mismatch"));
|
|
2118
|
-
const tenantKey = getTenantKeyFromRuntime(
|
|
1880
|
+
const tenantKey = getTenantKeyFromRuntime(url, runtime.configProvider);
|
|
1881
|
+
log.debug("[LoginFlow] Tenant key resolved", { tenantKey: tenantKey ?? "(null)" });
|
|
2119
1882
|
if (!tenantKey) {
|
|
2120
1883
|
throw new SanitizedError(
|
|
2121
1884
|
"TENANT_KEY_RESOLUTION_FAILED",
|
|
@@ -2123,7 +1886,15 @@ var LoginFlow = class {
|
|
|
2123
1886
|
new Error("Tenant key missing")
|
|
2124
1887
|
);
|
|
2125
1888
|
}
|
|
1889
|
+
log.debug("[LoginFlow] Resolving tenant config", { tenantKey });
|
|
2126
1890
|
const tenantConfig = await resolveTenantConfigCached(tenantKey, runtime.tenantResolver);
|
|
1891
|
+
log.debug("[LoginFlow] Tenant config resolved", {
|
|
1892
|
+
ok: !!tenantConfig,
|
|
1893
|
+
tenantId: tenantConfig?.tenantId,
|
|
1894
|
+
authServer: tenantConfig?.authServer ? "(set)" : "(empty)",
|
|
1895
|
+
clientId: tenantConfig?.client?.clientId,
|
|
1896
|
+
redirectUri: tenantConfig?.client?.redirectUri
|
|
1897
|
+
});
|
|
2127
1898
|
if (!tenantConfig) {
|
|
2128
1899
|
throw new SanitizedError(
|
|
2129
1900
|
"TENANT_CONFIG_RESOLUTION_FAILED",
|
|
@@ -2133,7 +1904,9 @@ var LoginFlow = class {
|
|
|
2133
1904
|
}
|
|
2134
1905
|
setTenantKey(tenantKey);
|
|
2135
1906
|
storeTenantConfig(tenantConfig);
|
|
1907
|
+
log.debug("[LoginFlow] Stored tenant config, initiating auth flow");
|
|
2136
1908
|
await initiateAuthFlow(tenantConfig);
|
|
1909
|
+
log.debug("[LoginFlow] Auth flow initiated (redirect should happen)");
|
|
2137
1910
|
return { completed: true };
|
|
2138
1911
|
}
|
|
2139
1912
|
};
|
|
@@ -2482,7 +2255,74 @@ function resetCookieWatcher() {
|
|
|
2482
2255
|
authCookies
|
|
2483
2256
|
});
|
|
2484
2257
|
}
|
|
2258
|
+
|
|
2259
|
+
// src/infrastructure/watchers/storage-watcher.ts
|
|
2260
|
+
var isWatching2 = false;
|
|
2261
|
+
var lastStorageCheck = null;
|
|
2262
|
+
var storageEventListener = null;
|
|
2263
|
+
function checkStorageCleared() {
|
|
2264
|
+
try {
|
|
2265
|
+
const hasAnyAuthData = Object.values(STORAGE_KEYS).some(
|
|
2266
|
+
(key) => getStorage(key) !== null
|
|
2267
|
+
);
|
|
2268
|
+
if (lastStorageCheck === "had_data" && !hasAnyAuthData) return true;
|
|
2269
|
+
lastStorageCheck = hasAnyAuthData ? "had_data" : "no_data";
|
|
2270
|
+
return false;
|
|
2271
|
+
} catch {
|
|
2272
|
+
return false;
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
function handleStorageEvent(event) {
|
|
2276
|
+
if (typeof window !== "undefined" && event.storageArea === window.sessionStorage) {
|
|
2277
|
+
const wasCleared = checkStorageCleared();
|
|
2278
|
+
if (wasCleared) {
|
|
2279
|
+
logger.info("Detected manual sessionStorage clear! Redirecting to login...");
|
|
2280
|
+
const cb = getSessionClearedCallback();
|
|
2281
|
+
if (cb) {
|
|
2282
|
+
Promise.resolve(cb()).catch((error) => {
|
|
2283
|
+
logger.error("Failed to redirect to login after manual clear", {
|
|
2284
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2285
|
+
});
|
|
2286
|
+
});
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
function startStorageWatcher() {
|
|
2292
|
+
if (isWatching2) return;
|
|
2293
|
+
isWatching2 = true;
|
|
2294
|
+
checkStorageCleared();
|
|
2295
|
+
storageEventListener = handleStorageEvent;
|
|
2296
|
+
window.addEventListener("storage", storageEventListener);
|
|
2297
|
+
const pollInterval = setInterval(() => {
|
|
2298
|
+
const logoutInProgress = typeof window !== "undefined" && window.localStorage.getItem(getStorageKey("logout_in_progress")) === "true";
|
|
2299
|
+
if (logoutInProgress) {
|
|
2300
|
+
logger.debug("Logout detected. Storage watcher will not trigger bootstrap.");
|
|
2301
|
+
return;
|
|
2302
|
+
}
|
|
2303
|
+
const wasCleared = checkStorageCleared();
|
|
2304
|
+
if (wasCleared) {
|
|
2305
|
+
logger.info("Detected manual sessionStorage clear (polling)! Redirecting to login...");
|
|
2306
|
+
clearInterval(pollInterval);
|
|
2307
|
+
const cb = getSessionClearedCallback();
|
|
2308
|
+
if (cb) {
|
|
2309
|
+
Promise.resolve(cb()).catch((error) => {
|
|
2310
|
+
logger.error("Failed to redirect to login after manual clear", {
|
|
2311
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2312
|
+
});
|
|
2313
|
+
if (!isWatching2) startStorageWatcher();
|
|
2314
|
+
});
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
}, 1e3);
|
|
2318
|
+
window.__tenneo_auth_storage_watcher_interval = pollInterval;
|
|
2319
|
+
}
|
|
2485
2320
|
function stopStorageWatcher() {
|
|
2321
|
+
isWatching2 = false;
|
|
2322
|
+
if (storageEventListener) {
|
|
2323
|
+
window.removeEventListener("storage", storageEventListener);
|
|
2324
|
+
storageEventListener = null;
|
|
2325
|
+
}
|
|
2486
2326
|
const win = window;
|
|
2487
2327
|
const intervalId = win.__tenneo_auth_storage_watcher_interval;
|
|
2488
2328
|
if (intervalId) {
|
|
@@ -2532,51 +2372,68 @@ function buildUrl(baseUrl, path) {
|
|
|
2532
2372
|
url.pathname = url.pathname.endsWith("/") ? `${url.pathname}${normalizedPath.slice(1)}` : `${url.pathname}${normalizedPath}`;
|
|
2533
2373
|
return url.toString();
|
|
2534
2374
|
}
|
|
2535
|
-
|
|
2375
|
+
function getCsrfToken() {
|
|
2536
2376
|
try {
|
|
2377
|
+
if (typeof document === "undefined") return null;
|
|
2378
|
+
const meta = document.querySelector('meta[name="csrf-token"]');
|
|
2379
|
+
if (meta?.content) return meta.content;
|
|
2380
|
+
const match = document.cookie.match(/(?:^|;\s*)XSRF-TOKEN=([^;]+)/i);
|
|
2381
|
+
if (match) return decodeURIComponent(match[1]);
|
|
2382
|
+
return null;
|
|
2383
|
+
} catch {
|
|
2384
|
+
return null;
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
async function callServerLogout(logoutUrl) {
|
|
2388
|
+
const csrfToken = getCsrfToken();
|
|
2389
|
+
async function doRequest(method) {
|
|
2390
|
+
const isPost = method === "POST";
|
|
2391
|
+
const headers = {
|
|
2392
|
+
"X-Requested-With": "XMLHttpRequest",
|
|
2393
|
+
Accept: "application/json, */*"
|
|
2394
|
+
};
|
|
2395
|
+
if (isPost) {
|
|
2396
|
+
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
|
2397
|
+
}
|
|
2398
|
+
if (csrfToken) {
|
|
2399
|
+
headers["X-CSRF-Token"] = csrfToken;
|
|
2400
|
+
}
|
|
2537
2401
|
const response = await fetch(logoutUrl, {
|
|
2538
|
-
method
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
"X-Requested-With": "XMLHttpRequest",
|
|
2542
|
-
Accept: "application/json"
|
|
2543
|
-
},
|
|
2402
|
+
method,
|
|
2403
|
+
mode: "cors",
|
|
2404
|
+
headers,
|
|
2544
2405
|
credentials: "include"
|
|
2545
2406
|
});
|
|
2407
|
+
if (!response.ok) {
|
|
2408
|
+
logger.warn("Server logout HTTP error", {
|
|
2409
|
+
method,
|
|
2410
|
+
status: response.status,
|
|
2411
|
+
statusText: response.statusText
|
|
2412
|
+
});
|
|
2413
|
+
return { success: false };
|
|
2414
|
+
}
|
|
2546
2415
|
const data = await response.json().catch(() => ({}));
|
|
2547
|
-
logger.info(
|
|
2416
|
+
logger.info(`Server logout response (${method})`, { response: data });
|
|
2548
2417
|
if (data && (data.success === true || data.logout === true)) {
|
|
2549
2418
|
return { success: true, response: data };
|
|
2550
2419
|
}
|
|
2551
|
-
logger.warn("Server logout response invalid
|
|
2420
|
+
logger.warn("Server logout response invalid payload", {
|
|
2421
|
+
method,
|
|
2422
|
+
response: data
|
|
2423
|
+
});
|
|
2552
2424
|
return { success: false, response: data };
|
|
2425
|
+
}
|
|
2426
|
+
try {
|
|
2427
|
+
const postResult = await doRequest("POST");
|
|
2428
|
+
if (postResult.success) return postResult;
|
|
2429
|
+
logger.debug("POST logout did not succeed, trying GET");
|
|
2430
|
+
const getResult = await doRequest("GET");
|
|
2431
|
+
return getResult;
|
|
2553
2432
|
} catch (error) {
|
|
2554
|
-
logger.
|
|
2433
|
+
logger.warn("Server logout failed (both POST and GET)", {
|
|
2555
2434
|
error: error instanceof Error ? error.message : String(error)
|
|
2556
2435
|
});
|
|
2557
|
-
|
|
2558
|
-
const response = await fetch(logoutUrl, {
|
|
2559
|
-
method: "GET",
|
|
2560
|
-
headers: {
|
|
2561
|
-
"X-Requested-With": "XMLHttpRequest",
|
|
2562
|
-
Accept: "application/json"
|
|
2563
|
-
},
|
|
2564
|
-
credentials: "include"
|
|
2565
|
-
});
|
|
2566
|
-
const data = await response.json().catch(() => ({}));
|
|
2567
|
-
logger.info("Server logout response (GET)", { response: data });
|
|
2568
|
-
if (data && (data.success === true || data.logout === true)) {
|
|
2569
|
-
return { success: true, response: data };
|
|
2570
|
-
}
|
|
2571
|
-
logger.warn("Server logout response invalid (GET)", { response: data });
|
|
2572
|
-
return { success: false, response: data };
|
|
2573
|
-
} catch (getError) {
|
|
2574
|
-
logger.warn("Server logout failed (both POST and GET)", {
|
|
2575
|
-
postError: error instanceof Error ? error.message : String(error),
|
|
2576
|
-
getError: getError instanceof Error ? getError.message : String(getError)
|
|
2577
|
-
});
|
|
2578
|
-
return { success: false };
|
|
2579
|
-
}
|
|
2436
|
+
return { success: false };
|
|
2580
2437
|
}
|
|
2581
2438
|
}
|
|
2582
2439
|
function performLocalLogoutCleanup() {
|
|
@@ -2589,22 +2446,50 @@ function performLocalLogoutCleanup() {
|
|
|
2589
2446
|
});
|
|
2590
2447
|
}
|
|
2591
2448
|
clearClientCookies();
|
|
2592
|
-
|
|
2449
|
+
try {
|
|
2450
|
+
clearAuthStorage();
|
|
2451
|
+
} catch (error) {
|
|
2452
|
+
logger.warn("clearAuthStorage failed (ignored)", {
|
|
2453
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2454
|
+
});
|
|
2455
|
+
}
|
|
2593
2456
|
logger.info("Local logout cleanup completed");
|
|
2594
2457
|
}
|
|
2458
|
+
function acquireLogoutLock() {
|
|
2459
|
+
const LOCK_KEY = getStorageKey("logout_lock");
|
|
2460
|
+
const now = Date.now();
|
|
2461
|
+
const existingLock = getStorage(LOCK_KEY);
|
|
2462
|
+
if (existingLock) {
|
|
2463
|
+
const lockTime = Number(existingLock);
|
|
2464
|
+
if (!Number.isNaN(lockTime) && now - lockTime < 5e3) {
|
|
2465
|
+
logger.debug("Logout lock active \u2013 skipping duplicate logout", {
|
|
2466
|
+
now,
|
|
2467
|
+
lockTime
|
|
2468
|
+
});
|
|
2469
|
+
return false;
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
setStorage(LOCK_KEY, String(now));
|
|
2473
|
+
return true;
|
|
2474
|
+
}
|
|
2475
|
+
function releaseLogoutLock() {
|
|
2476
|
+
try {
|
|
2477
|
+
removeStorage(getStorageKey("logout_lock"));
|
|
2478
|
+
} catch {
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2595
2481
|
async function logout(tenantKey) {
|
|
2596
|
-
setStorage(getStorageKey("logout_in_progress"), "true");
|
|
2597
2482
|
setStorage(getStorageKey("force_login"), "true");
|
|
2598
|
-
if (tenantKey?.trim())
|
|
2599
|
-
|
|
2600
|
-
|
|
2483
|
+
if (tenantKey?.trim()) {
|
|
2484
|
+
setStorage(getStorageKey("preserved_tenant_key"), tenantKey.trim());
|
|
2485
|
+
}
|
|
2486
|
+
if (!acquireLogoutLock()) {
|
|
2601
2487
|
return { success: true, message: "Logout already in progress." };
|
|
2602
2488
|
}
|
|
2603
|
-
setStorage(getStorageKey("logout_processing"), "true");
|
|
2604
2489
|
try {
|
|
2605
2490
|
stopStorageWatcher();
|
|
2606
2491
|
stopCookieWatcher();
|
|
2607
|
-
const apiAuthBaseUrl = Config.
|
|
2492
|
+
const apiAuthBaseUrl = Config.getAuthServerUrl();
|
|
2608
2493
|
let serverLogoutSuccess = false;
|
|
2609
2494
|
let serverResponse;
|
|
2610
2495
|
if (apiAuthBaseUrl) {
|
|
@@ -2613,20 +2498,45 @@ async function logout(tenantKey) {
|
|
|
2613
2498
|
const logoutResult = await callServerLogout(logoutUrl);
|
|
2614
2499
|
serverLogoutSuccess = logoutResult.success;
|
|
2615
2500
|
serverResponse = logoutResult.response;
|
|
2501
|
+
if (!serverLogoutSuccess) {
|
|
2502
|
+
logger.warn("Server logout failed \u2013 session may still exist", {
|
|
2503
|
+
logoutUrl,
|
|
2504
|
+
serverResponse
|
|
2505
|
+
});
|
|
2506
|
+
}
|
|
2507
|
+
} else {
|
|
2508
|
+
logger.warn("API auth base URL not configured, performing local logout only");
|
|
2616
2509
|
}
|
|
2617
2510
|
performLocalLogoutCleanup();
|
|
2618
2511
|
const preservedTenantKey = getStorage(getStorageKey("preserved_tenant_key"));
|
|
2619
2512
|
if (preservedTenantKey) {
|
|
2620
|
-
|
|
2513
|
+
const propsKey = getStorageKey("props_config");
|
|
2514
|
+
let existing = {};
|
|
2515
|
+
try {
|
|
2516
|
+
const raw = getStorage(propsKey);
|
|
2517
|
+
if (raw) {
|
|
2518
|
+
existing = JSON.parse(raw);
|
|
2519
|
+
}
|
|
2520
|
+
} catch {
|
|
2521
|
+
existing = {};
|
|
2522
|
+
}
|
|
2523
|
+
const merged = {
|
|
2524
|
+
...existing,
|
|
2525
|
+
tenantKey: preservedTenantKey
|
|
2526
|
+
};
|
|
2527
|
+
setStorage(propsKey, JSON.stringify(merged));
|
|
2621
2528
|
removeStorage(getStorageKey("preserved_tenant_key"));
|
|
2622
2529
|
}
|
|
2623
2530
|
resetCookieWatcher();
|
|
2624
|
-
|
|
2531
|
+
startStorageWatcher();
|
|
2532
|
+
releaseLogoutLock();
|
|
2625
2533
|
logger.info("Logout completed \u2013 flags set, storage cleared, fresh login required", {
|
|
2626
2534
|
serverLogoutSuccess,
|
|
2627
2535
|
serverResponse
|
|
2628
2536
|
});
|
|
2629
2537
|
emitAuthEvent(AuthEventNames.LOGOUT_COMPLETED, {
|
|
2538
|
+
serverLogoutSuccess,
|
|
2539
|
+
tenantKey: getStorage(getStorageKey("preserved_tenant_key")) || void 0,
|
|
2630
2540
|
message: serverLogoutSuccess ? "Server logout success" : "Local logout only"
|
|
2631
2541
|
});
|
|
2632
2542
|
return {
|
|
@@ -2641,10 +2551,24 @@ async function logout(tenantKey) {
|
|
|
2641
2551
|
performLocalLogoutCleanup();
|
|
2642
2552
|
const preservedTenantKey = getStorage(getStorageKey("preserved_tenant_key"));
|
|
2643
2553
|
if (preservedTenantKey) {
|
|
2644
|
-
|
|
2554
|
+
const propsKey = getStorageKey("props_config");
|
|
2555
|
+
let existing = {};
|
|
2556
|
+
try {
|
|
2557
|
+
const raw = getStorage(propsKey);
|
|
2558
|
+
if (raw) {
|
|
2559
|
+
existing = JSON.parse(raw);
|
|
2560
|
+
}
|
|
2561
|
+
} catch {
|
|
2562
|
+
existing = {};
|
|
2563
|
+
}
|
|
2564
|
+
const merged = {
|
|
2565
|
+
...existing,
|
|
2566
|
+
tenantKey: preservedTenantKey
|
|
2567
|
+
};
|
|
2568
|
+
setStorage(propsKey, JSON.stringify(merged));
|
|
2645
2569
|
removeStorage(getStorageKey("preserved_tenant_key"));
|
|
2646
2570
|
}
|
|
2647
|
-
|
|
2571
|
+
releaseLogoutLock();
|
|
2648
2572
|
return {
|
|
2649
2573
|
success: true,
|
|
2650
2574
|
message: "Logged out locally due to an error. Fresh login required."
|
|
@@ -2664,16 +2588,16 @@ function useAuthContext() {
|
|
|
2664
2588
|
var ongoingRequests = /* @__PURE__ */ new Map();
|
|
2665
2589
|
var DEFAULT_SCOPES2 = OAUTH_CONSTANTS.SCOPES;
|
|
2666
2590
|
function getResolvedTenantBaseUrl() {
|
|
2667
|
-
let base = Config.
|
|
2591
|
+
let base = Config.getApiBaseUrl();
|
|
2668
2592
|
if (typeof window !== "undefined" && (!base || base.startsWith("/"))) {
|
|
2669
|
-
base = window.location.origin + (base || "
|
|
2593
|
+
base = window.location.origin + (base || "");
|
|
2670
2594
|
}
|
|
2671
2595
|
return base;
|
|
2672
2596
|
}
|
|
2673
2597
|
var PUBLIC_CODE_PREFIX = "public-";
|
|
2674
2598
|
function getTenantByCodeUrl(tenantCode) {
|
|
2675
2599
|
const apiTenantResolutionBaseUrl = getResolvedTenantBaseUrl();
|
|
2676
|
-
const base = apiTenantResolutionBaseUrl.replace(/\/api
|
|
2600
|
+
const base = (apiTenantResolutionBaseUrl || "").replace(/\/api(?:\/v1)?\/?$/, "") || apiTenantResolutionBaseUrl;
|
|
2677
2601
|
return `${base}/api/v1/tenant/public/tenants/by-code/${encodeURIComponent(tenantCode)}`;
|
|
2678
2602
|
}
|
|
2679
2603
|
async function resolveTenant(tenantKey) {
|
|
@@ -2709,7 +2633,9 @@ async function resolveTenant(tenantKey) {
|
|
|
2709
2633
|
if (!tenant.id || !tenant.clientCode) return null;
|
|
2710
2634
|
const authServer = Config.getAuthServerUrl();
|
|
2711
2635
|
const redirectUri = Config.getRedirectUri();
|
|
2712
|
-
if (!authServer || !redirectUri)
|
|
2636
|
+
if (!authServer || !redirectUri) {
|
|
2637
|
+
return null;
|
|
2638
|
+
}
|
|
2713
2639
|
const clientCodeWithPrefix = tenant.clientCode.startsWith(PUBLIC_CODE_PREFIX) ? tenant.clientCode : `${PUBLIC_CODE_PREFIX}${tenant.clientCode}`;
|
|
2714
2640
|
const config = {
|
|
2715
2641
|
tenantId: tenant.id,
|
|
@@ -2722,6 +2648,7 @@ async function resolveTenant(tenantKey) {
|
|
|
2722
2648
|
scopes: DEFAULT_SCOPES2
|
|
2723
2649
|
}
|
|
2724
2650
|
};
|
|
2651
|
+
console.log("config====", config);
|
|
2725
2652
|
logger.debug("Resolved tenant config", { tenantCode });
|
|
2726
2653
|
return config;
|
|
2727
2654
|
} catch (error) {
|
|
@@ -2783,13 +2710,10 @@ function createBrowserUrlProvider() {
|
|
|
2783
2710
|
}
|
|
2784
2711
|
function createConfigProvider() {
|
|
2785
2712
|
return {
|
|
2786
|
-
getApiBaseUrl: () => Config.
|
|
2713
|
+
getApiBaseUrl: () => Config.getApiBaseUrl(),
|
|
2787
2714
|
getAuthServerUrl: () => Config.getAuthServerUrl(),
|
|
2788
2715
|
getRedirectUri: () => Config.getRedirectUri(),
|
|
2789
|
-
|
|
2790
|
-
getTenantId: () => Config.getTenantId(),
|
|
2791
|
-
getClientCode: () => Config.getClientCode(),
|
|
2792
|
-
getBasePath: () => Config.getBasePath()
|
|
2716
|
+
getClientCode: () => Config.getClientCode()
|
|
2793
2717
|
};
|
|
2794
2718
|
}
|
|
2795
2719
|
function createTenantResolver() {
|
|
@@ -2953,6 +2877,9 @@ function AuthProvider({
|
|
|
2953
2877
|
children,
|
|
2954
2878
|
autoInit = true,
|
|
2955
2879
|
tenantCode,
|
|
2880
|
+
apiBaseUrl,
|
|
2881
|
+
authServerUrl,
|
|
2882
|
+
callbackUrl,
|
|
2956
2883
|
appId = "",
|
|
2957
2884
|
storageAdapter
|
|
2958
2885
|
}) {
|
|
@@ -2964,13 +2891,40 @@ function AuthProvider({
|
|
|
2964
2891
|
const initRanRef = useRef(false);
|
|
2965
2892
|
const engineRef = useRef(null);
|
|
2966
2893
|
useLayoutEffect(() => {
|
|
2967
|
-
|
|
2968
|
-
|
|
2894
|
+
logger.debug("[AuthProvider] Host config props", {
|
|
2895
|
+
tenantCode: tenantCode ?? "(not provided)",
|
|
2896
|
+
apiBaseUrl: apiBaseUrl ? apiBaseUrl : "(empty)",
|
|
2897
|
+
authServerUrl: authServerUrl ? authServerUrl : "(empty)",
|
|
2898
|
+
callbackUrl: callbackUrl ? callbackUrl : "(empty)"
|
|
2899
|
+
});
|
|
2900
|
+
if (!authServerUrl || !authServerUrl.trim()) {
|
|
2901
|
+
logger.warn("[AuthProvider] authServerUrl missing from host props");
|
|
2902
|
+
}
|
|
2903
|
+
if (!callbackUrl || !callbackUrl.trim()) {
|
|
2904
|
+
logger.warn("[AuthProvider] callbackUrl missing from host props");
|
|
2969
2905
|
}
|
|
2906
|
+
setConfig({
|
|
2907
|
+
...tenantCode ? { tenantCode } : {},
|
|
2908
|
+
...apiBaseUrl ? { apiBaseUrl } : {},
|
|
2909
|
+
...authServerUrl ? { authServerUrl } : {},
|
|
2910
|
+
...callbackUrl ? { callbackUrl } : {}
|
|
2911
|
+
});
|
|
2970
2912
|
return () => {
|
|
2971
2913
|
clearConfigOverrides();
|
|
2972
2914
|
};
|
|
2973
|
-
}, [tenantCode]);
|
|
2915
|
+
}, [tenantCode, apiBaseUrl, authServerUrl, callbackUrl]);
|
|
2916
|
+
useEffect(() => {
|
|
2917
|
+
try {
|
|
2918
|
+
const payload = {
|
|
2919
|
+
tenantCode: tenantCode ?? "",
|
|
2920
|
+
apiBaseUrl: apiBaseUrl ?? "",
|
|
2921
|
+
authServerUrl: authServerUrl ?? "",
|
|
2922
|
+
callbackUrl: callbackUrl ?? ""
|
|
2923
|
+
};
|
|
2924
|
+
setStorage(getStorageKey("host_config"), JSON.stringify(payload));
|
|
2925
|
+
} catch {
|
|
2926
|
+
}
|
|
2927
|
+
}, [tenantCode, apiBaseUrl, authServerUrl, callbackUrl]);
|
|
2974
2928
|
useLayoutEffect(() => {
|
|
2975
2929
|
setStorageKeyPrefix(resolvedTenantKey ?? "");
|
|
2976
2930
|
const adapter = storageAdapter !== void 0 && storageAdapter !== null ? storageAdapter : createSecureSessionStorageAdapter(namespace);
|
|
@@ -3431,6 +3385,6 @@ function useAuthInit() {
|
|
|
3431
3385
|
);
|
|
3432
3386
|
}
|
|
3433
3387
|
|
|
3434
|
-
export { AuthCallback, AuthEventNames, AuthProvider, Config, OAUTH_CONSTANTS, ProtectedRoute, STORAGE_KEYS2 as STORAGE_KEYS, STORAGE_KEY_PREFIX, SanitizedError, bootstrap, buildStorageKey, createAuthEngine, createCookieStorageAdapter, createMemoryStorageAdapter, createOAuth2PkceStrategy, createSecureSessionStorageAdapter, emitAuthEvent, enforceHttps, ensureValidAccessToken, extractTenantKey, getAccessToken2 as getAccessToken, getAuthRuntime, getConfig,
|
|
3388
|
+
export { AuthCallback, AuthEventNames, AuthProvider, Config, OAUTH_CONSTANTS, ProtectedRoute, STORAGE_KEYS2 as STORAGE_KEYS, STORAGE_KEY_PREFIX, SanitizedError, bootstrap, buildStorageKey, createAuthEngine, createCookieStorageAdapter, createMemoryStorageAdapter, createOAuth2PkceStrategy, createSecureSessionStorageAdapter, emitAuthEvent, enforceHttps, ensureValidAccessToken, extractTenantKey, getAccessToken2 as getAccessToken, getAuthRuntime, getConfig, getStorageAdapter, getStorageNamespace, getAccessToken as getStoredAccessToken, isAccessTokenExpired, isCallbackUrl, logout, refreshAccessToken, resetCookieWatcher, resolveConfig, resolveTenant, sanitizeErrorMessage, setAuthRuntime, setConfig, setStorageContext, startCookieWatcher, stopCookieWatcher, subscribeAuthEvent, useAuth, useAuthContext, useAuthInit };
|
|
3435
3389
|
//# sourceMappingURL=index.mjs.map
|
|
3436
3390
|
//# sourceMappingURL=index.mjs.map
|