@uipath/auth 1.1.0 → 1.196.0
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/dist/authContext.d.ts +39 -0
- package/dist/catch-error.d.ts +5 -0
- package/dist/clientCredentials.d.ts +9 -0
- package/dist/config.d.ts +73 -0
- package/dist/constants.d.ts +10 -0
- package/dist/envAuth.d.ts +75 -0
- package/dist/getBaseHtml.d.ts +7 -0
- package/dist/index.browser.d.ts +10 -0
- package/dist/index.browser.js +283 -110
- package/dist/index.d.ts +30 -0
- package/dist/index.js +493 -204
- package/dist/interactive.d.ts +102 -0
- package/dist/loginStatus.d.ts +80 -0
- package/dist/logout.d.ts +44 -0
- package/dist/oidc.d.ts +5 -0
- package/dist/robotClientFallback.d.ts +64 -0
- package/dist/selectTenant.d.ts +8 -0
- package/dist/server.d.ts +8 -0
- package/dist/strategies/auth-strategy.d.ts +7 -0
- package/dist/strategies/browser-strategy.d.ts +6 -0
- package/dist/strategies/node-strategy.d.ts +6 -0
- package/dist/tenantSelection.d.ts +17 -0
- package/dist/tokenExchange.d.ts +13 -0
- package/dist/tokenRefresh.d.ts +27 -0
- package/dist/types.d.ts +5 -0
- package/dist/utils/envFile.d.ts +106 -0
- package/dist/utils/jwt.d.ts +43 -0
- package/dist/utils/platform.d.ts +36 -0
- package/package.json +38 -43
package/dist/index.browser.js
CHANGED
|
@@ -69,32 +69,7 @@ class InvalidBaseUrlError extends Error {
|
|
|
69
69
|
this.name = "InvalidBaseUrlError";
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
-
var DEFAULT_SCOPES = [
|
|
73
|
-
"offline_access",
|
|
74
|
-
"ProcessMining",
|
|
75
|
-
"OrchestratorApiUserAccess",
|
|
76
|
-
"StudioWebBackend",
|
|
77
|
-
"IdentityServerApi",
|
|
78
|
-
"ConnectionService",
|
|
79
|
-
"DataService",
|
|
80
|
-
"DataServiceApiUserAccess",
|
|
81
|
-
"DocumentUnderstanding",
|
|
82
|
-
"EnterpriseContextService",
|
|
83
|
-
"Directory",
|
|
84
|
-
"JamJamApi",
|
|
85
|
-
"LLMGateway",
|
|
86
|
-
"LLMOps",
|
|
87
|
-
"OMS",
|
|
88
|
-
"RCS.FolderAuthorization",
|
|
89
|
-
"RCS.TagsManagement",
|
|
90
|
-
"TestmanagerApiUserAccess",
|
|
91
|
-
"AutomationSolutions",
|
|
92
|
-
"StudioWebTypeCacheService",
|
|
93
|
-
"Docs.GPT.Search",
|
|
94
|
-
"Insights",
|
|
95
|
-
"ReferenceToken",
|
|
96
|
-
"Audit.Read"
|
|
97
|
-
];
|
|
72
|
+
var DEFAULT_SCOPES = ["openid", "profile", "offline_access"];
|
|
98
73
|
var normalizeAndValidateBaseUrl = (rawUrl) => {
|
|
99
74
|
let baseUrl = rawUrl;
|
|
100
75
|
if (baseUrl.endsWith("/identity_/")) {
|
|
@@ -144,7 +119,8 @@ var resolveConfigAsync = async ({
|
|
|
144
119
|
if (!clientSecret && fileAuth.clientSecret) {
|
|
145
120
|
clientSecret = fileAuth.clientSecret;
|
|
146
121
|
}
|
|
147
|
-
const
|
|
122
|
+
const isExternalAppAuth = clientId !== DEFAULT_CLIENT_ID && Boolean(clientSecret);
|
|
123
|
+
const scopes = customScopes && customScopes.length > 0 ? customScopes : fileAuth.scopes && fileAuth.scopes.length > 0 ? fileAuth.scopes : isExternalAppAuth ? [] : DEFAULT_SCOPES;
|
|
148
124
|
return {
|
|
149
125
|
clientId,
|
|
150
126
|
clientSecret,
|
|
@@ -352,11 +328,11 @@ var parseResourceUrl = (url) => {
|
|
|
352
328
|
if (error || !parsed)
|
|
353
329
|
return;
|
|
354
330
|
const segments = parsed.pathname.split("/").filter(Boolean);
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
331
|
+
return {
|
|
332
|
+
baseUrl: parsed.origin,
|
|
333
|
+
organizationName: segments[0],
|
|
334
|
+
tenantName: segments[1]
|
|
335
|
+
};
|
|
360
336
|
};
|
|
361
337
|
var defaultLoadModule = async () => {
|
|
362
338
|
const [error, mod] = await catchError(() => import("@uipath/robot-client"));
|
|
@@ -407,6 +383,7 @@ var tryRobotClientFallback = async (options = {}) => {
|
|
|
407
383
|
}
|
|
408
384
|
let organizationIdFromToken;
|
|
409
385
|
let tenantIdFromToken;
|
|
386
|
+
let issuerFromToken;
|
|
410
387
|
const [jwtError, claims] = catchError(() => parseJWT(accessToken));
|
|
411
388
|
if (!jwtError && claims) {
|
|
412
389
|
const rawOrgId = claims.prtId ?? claims.organizationId ?? claims.prt_id;
|
|
@@ -417,6 +394,10 @@ var tryRobotClientFallback = async (options = {}) => {
|
|
|
417
394
|
if (typeof tenantClaim === "string" && tenantClaim.length > 0) {
|
|
418
395
|
tenantIdFromToken = tenantClaim;
|
|
419
396
|
}
|
|
397
|
+
const issClaim = claims.iss;
|
|
398
|
+
if (typeof issClaim === "string" && issClaim.length > 0) {
|
|
399
|
+
issuerFromToken = issClaim;
|
|
400
|
+
}
|
|
420
401
|
}
|
|
421
402
|
printNoticeOnce();
|
|
422
403
|
return {
|
|
@@ -425,7 +406,8 @@ var tryRobotClientFallback = async (options = {}) => {
|
|
|
425
406
|
organizationName: parsedUrl.organizationName,
|
|
426
407
|
organizationId: organizationIdFromToken ?? parsedUrl.organizationName,
|
|
427
408
|
tenantName: parsedUrl.tenantName,
|
|
428
|
-
tenantId: tenantIdFromToken
|
|
409
|
+
tenantId: tenantIdFromToken,
|
|
410
|
+
issuer: issuerFromToken
|
|
429
411
|
};
|
|
430
412
|
} catch {
|
|
431
413
|
return;
|
|
@@ -527,7 +509,7 @@ var probeAsync = async (fs, candidate) => {
|
|
|
527
509
|
};
|
|
528
510
|
}
|
|
529
511
|
};
|
|
530
|
-
var resolveEnvFileLocationAsync = async (envFilePath = DEFAULT_ENV_FILENAME) => {
|
|
512
|
+
var resolveEnvFileLocationAsync = async (envFilePath = DEFAULT_ENV_FILENAME, opts) => {
|
|
531
513
|
const fs = getFileSystem2();
|
|
532
514
|
if (fs.path.isAbsolute(envFilePath)) {
|
|
533
515
|
const probe2 = await probeAsync(fs, envFilePath);
|
|
@@ -538,7 +520,7 @@ var resolveEnvFileLocationAsync = async (envFilePath = DEFAULT_ENV_FILENAME) =>
|
|
|
538
520
|
...probe2.unusable ? { unusable: probe2.unusable } : {}
|
|
539
521
|
};
|
|
540
522
|
}
|
|
541
|
-
const cwd = fs.env.cwd();
|
|
523
|
+
const cwd = opts?.cwd ?? fs.env.cwd();
|
|
542
524
|
let searchDir = cwd;
|
|
543
525
|
while (true) {
|
|
544
526
|
const candidate = fs.path.join(searchDir, envFilePath);
|
|
@@ -568,8 +550,8 @@ var resolveEnvFileLocationAsync = async (envFilePath = DEFAULT_ENV_FILENAME) =>
|
|
|
568
550
|
...probe.unusable ? { unusable: probe.unusable } : {}
|
|
569
551
|
};
|
|
570
552
|
};
|
|
571
|
-
var resolveEnvFilePathAsync = async (envFilePath = DEFAULT_ENV_FILENAME) => {
|
|
572
|
-
const location = await resolveEnvFileLocationAsync(envFilePath);
|
|
553
|
+
var resolveEnvFilePathAsync = async (envFilePath = DEFAULT_ENV_FILENAME, opts) => {
|
|
554
|
+
const location = await resolveEnvFileLocationAsync(envFilePath, opts);
|
|
573
555
|
if (location.exists) {
|
|
574
556
|
return { absolutePath: location.absolutePath };
|
|
575
557
|
}
|
|
@@ -653,6 +635,129 @@ function normalizeTokenRefreshFailure() {
|
|
|
653
635
|
function normalizeTokenRefreshUnavailableFailure() {
|
|
654
636
|
return "token refresh failed before authentication completed";
|
|
655
637
|
}
|
|
638
|
+
function errorMessage(error) {
|
|
639
|
+
return error instanceof Error ? error.message : String(error);
|
|
640
|
+
}
|
|
641
|
+
function computeExpirationThreshold(ensureTokenValidityMinutes) {
|
|
642
|
+
return new Date(Date.now() + (ensureTokenValidityMinutes ?? 0) * 60 * 1000);
|
|
643
|
+
}
|
|
644
|
+
async function runRefreshLocked(inputs) {
|
|
645
|
+
const {
|
|
646
|
+
absolutePath,
|
|
647
|
+
refreshToken: callerRefreshToken,
|
|
648
|
+
customAuthority,
|
|
649
|
+
ensureTokenValidityMinutes,
|
|
650
|
+
loadEnvFile,
|
|
651
|
+
saveEnvFile,
|
|
652
|
+
refreshFn,
|
|
653
|
+
resolveConfig
|
|
654
|
+
} = inputs;
|
|
655
|
+
const expirationThreshold = computeExpirationThreshold(ensureTokenValidityMinutes);
|
|
656
|
+
let fresh;
|
|
657
|
+
try {
|
|
658
|
+
fresh = await loadEnvFile({ envPath: absolutePath });
|
|
659
|
+
} catch (error) {
|
|
660
|
+
return {
|
|
661
|
+
kind: "fail",
|
|
662
|
+
status: {
|
|
663
|
+
loginStatus: "Refresh Failed",
|
|
664
|
+
hint: "Could not read the auth file while refreshing. Retry, or run 'uip login' to re-authenticate.",
|
|
665
|
+
tokenRefresh: {
|
|
666
|
+
attempted: false,
|
|
667
|
+
success: false,
|
|
668
|
+
errorMessage: `auth file read failed: ${errorMessage(error)}`
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
const freshAccess = fresh.UIPATH_ACCESS_TOKEN;
|
|
674
|
+
const freshExp = freshAccess ? getTokenExpiration(freshAccess) : undefined;
|
|
675
|
+
if (freshAccess && freshExp && freshExp > expirationThreshold) {
|
|
676
|
+
return {
|
|
677
|
+
kind: "ok",
|
|
678
|
+
accessToken: freshAccess,
|
|
679
|
+
refreshToken: fresh.UIPATH_REFRESH_TOKEN ?? callerRefreshToken,
|
|
680
|
+
expiration: freshExp,
|
|
681
|
+
tokenRefresh: { attempted: false, success: true }
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
const tokenForIdP = fresh.UIPATH_REFRESH_TOKEN ?? callerRefreshToken;
|
|
685
|
+
let refreshedAccess;
|
|
686
|
+
let refreshedRefresh;
|
|
687
|
+
try {
|
|
688
|
+
const config = await resolveConfig({ customAuthority });
|
|
689
|
+
const refreshed = await refreshFn({
|
|
690
|
+
refreshToken: tokenForIdP,
|
|
691
|
+
tokenEndpoint: config.tokenEndpoint,
|
|
692
|
+
clientId: config.clientId,
|
|
693
|
+
expectedAuthority: customAuthority
|
|
694
|
+
});
|
|
695
|
+
refreshedAccess = refreshed.accessToken;
|
|
696
|
+
refreshedRefresh = refreshed.refreshToken;
|
|
697
|
+
} catch (error) {
|
|
698
|
+
const isOAuthFailure = isTokenRefreshOAuthFailure(error);
|
|
699
|
+
const hint = isOAuthFailure ? "Run 'uip login' to re-authenticate — the stored refresh token is invalid or expired." : "Token refresh failed. Check your network connection, then retry or run 'uip login' to re-authenticate.";
|
|
700
|
+
const message = isOAuthFailure ? normalizeTokenRefreshFailure() : normalizeTokenRefreshUnavailableFailure();
|
|
701
|
+
return {
|
|
702
|
+
kind: "fail",
|
|
703
|
+
status: {
|
|
704
|
+
loginStatus: "Refresh Failed",
|
|
705
|
+
hint,
|
|
706
|
+
tokenRefresh: {
|
|
707
|
+
attempted: true,
|
|
708
|
+
success: false,
|
|
709
|
+
errorMessage: message
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
const refreshedExp = getTokenExpiration(refreshedAccess);
|
|
715
|
+
if (!refreshedExp || refreshedExp <= new Date) {
|
|
716
|
+
return {
|
|
717
|
+
kind: "fail",
|
|
718
|
+
status: {
|
|
719
|
+
loginStatus: "Refresh Failed",
|
|
720
|
+
hint: "The identity server returned an unusable token. Run 'uip login' to re-authenticate.",
|
|
721
|
+
tokenRefresh: {
|
|
722
|
+
attempted: true,
|
|
723
|
+
success: false,
|
|
724
|
+
errorMessage: "refreshed token has no valid expiration claim"
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
try {
|
|
730
|
+
await saveEnvFile({
|
|
731
|
+
envPath: absolutePath,
|
|
732
|
+
data: {
|
|
733
|
+
UIPATH_ACCESS_TOKEN: refreshedAccess,
|
|
734
|
+
UIPATH_REFRESH_TOKEN: refreshedRefresh
|
|
735
|
+
},
|
|
736
|
+
merge: true
|
|
737
|
+
});
|
|
738
|
+
return {
|
|
739
|
+
kind: "ok",
|
|
740
|
+
accessToken: refreshedAccess,
|
|
741
|
+
refreshToken: refreshedRefresh,
|
|
742
|
+
expiration: refreshedExp,
|
|
743
|
+
tokenRefresh: { attempted: true, success: true }
|
|
744
|
+
};
|
|
745
|
+
} catch (error) {
|
|
746
|
+
const msg = errorMessage(error);
|
|
747
|
+
return {
|
|
748
|
+
kind: "ok",
|
|
749
|
+
accessToken: refreshedAccess,
|
|
750
|
+
refreshToken: refreshedRefresh,
|
|
751
|
+
expiration: refreshedExp,
|
|
752
|
+
persistenceWarning: `Access token refreshed in memory but could not be written to ${absolutePath}: ${msg}. The next CLI invocation will fail until the file can be updated — run 'uip login' to re-authenticate.`,
|
|
753
|
+
tokenRefresh: {
|
|
754
|
+
attempted: true,
|
|
755
|
+
success: true,
|
|
756
|
+
errorMessage: `persistence failed: ${msg}`
|
|
757
|
+
}
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
}
|
|
656
761
|
var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
|
|
657
762
|
const {
|
|
658
763
|
resolveEnvFilePath = resolveEnvFilePathAsync,
|
|
@@ -683,6 +788,7 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
|
|
|
683
788
|
organizationId: robotCreds.organizationId,
|
|
684
789
|
tenantName: robotCreds.tenantName,
|
|
685
790
|
tenantId: robotCreds.tenantId,
|
|
791
|
+
issuer: robotCreds.issuer,
|
|
686
792
|
expiration: expiration2,
|
|
687
793
|
source: "robot" /* Robot */
|
|
688
794
|
};
|
|
@@ -704,6 +810,7 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
|
|
|
704
810
|
organizationId: robotCreds.organizationId,
|
|
705
811
|
tenantName: robotCreds.tenantName,
|
|
706
812
|
tenantId: robotCreds.tenantId,
|
|
813
|
+
issuer: robotCreds.issuer,
|
|
707
814
|
expiration: expiration2,
|
|
708
815
|
source: "robot" /* Robot */
|
|
709
816
|
};
|
|
@@ -727,73 +834,103 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
|
|
|
727
834
|
let refreshToken = credentials.UIPATH_REFRESH_TOKEN;
|
|
728
835
|
let expiration = getTokenExpiration(accessToken);
|
|
729
836
|
let persistenceWarning;
|
|
837
|
+
let lockReleaseFailed = false;
|
|
730
838
|
let tokenRefresh;
|
|
731
|
-
const
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
839
|
+
const outerThreshold = computeExpirationThreshold(ensureTokenValidityMinutes);
|
|
840
|
+
const tryGlobalCredsHint = async () => {
|
|
841
|
+
const fs = getFs();
|
|
842
|
+
const globalPath = fs.path.join(fs.env.homedir(), envFilePath);
|
|
843
|
+
if (absolutePath === globalPath)
|
|
844
|
+
return;
|
|
845
|
+
if (!await fs.exists(globalPath))
|
|
846
|
+
return;
|
|
735
847
|
try {
|
|
736
|
-
const
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
const
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
refreshedAccess = refreshed.accessToken;
|
|
746
|
-
refreshedRefresh = refreshed.refreshToken;
|
|
747
|
-
} catch (error) {
|
|
748
|
-
const isOAuthFailure = isTokenRefreshOAuthFailure(error);
|
|
749
|
-
const hint = isOAuthFailure ? "Run 'uip login' to re-authenticate — the stored refresh token is invalid or expired." : "Token refresh failed. Check your network connection, then retry or run 'uip login' to re-authenticate.";
|
|
750
|
-
const errorMessage = isOAuthFailure ? normalizeTokenRefreshFailure() : normalizeTokenRefreshUnavailableFailure();
|
|
751
|
-
return {
|
|
752
|
-
loginStatus: "Refresh Failed",
|
|
753
|
-
hint,
|
|
754
|
-
tokenRefresh: {
|
|
755
|
-
attempted: true,
|
|
756
|
-
success: false,
|
|
757
|
-
errorMessage
|
|
758
|
-
}
|
|
759
|
-
};
|
|
848
|
+
const globalCreds = await loadEnvFile({ envPath: globalPath });
|
|
849
|
+
if (!globalCreds.UIPATH_ACCESS_TOKEN)
|
|
850
|
+
return;
|
|
851
|
+
const globalExp = getTokenExpiration(globalCreds.UIPATH_ACCESS_TOKEN);
|
|
852
|
+
if (globalExp && globalExp <= new Date)
|
|
853
|
+
return;
|
|
854
|
+
return `Local credentials file at ${absolutePath} has expired credentials. Valid credentials exist in ${globalPath}. Remove the local file or run 'uip login' to re-authenticate.`;
|
|
855
|
+
} catch {
|
|
856
|
+
return;
|
|
760
857
|
}
|
|
761
|
-
|
|
762
|
-
|
|
858
|
+
};
|
|
859
|
+
if (expiration && expiration <= outerThreshold && refreshToken) {
|
|
860
|
+
let release;
|
|
861
|
+
try {
|
|
862
|
+
release = await getFs().acquireLock(absolutePath);
|
|
863
|
+
} catch (error) {
|
|
864
|
+
const msg = errorMessage(error);
|
|
865
|
+
const globalHint = await tryGlobalCredsHint();
|
|
866
|
+
if (globalHint) {
|
|
867
|
+
return {
|
|
868
|
+
loginStatus: "Expired",
|
|
869
|
+
accessToken,
|
|
870
|
+
refreshToken,
|
|
871
|
+
baseUrl: credentials.UIPATH_URL,
|
|
872
|
+
organizationName: credentials.UIPATH_ORGANIZATION_NAME,
|
|
873
|
+
organizationId: credentials.UIPATH_ORGANIZATION_ID,
|
|
874
|
+
tenantName: credentials.UIPATH_TENANT_NAME,
|
|
875
|
+
tenantId: credentials.UIPATH_TENANT_ID,
|
|
876
|
+
expiration,
|
|
877
|
+
source: "file" /* File */,
|
|
878
|
+
hint: globalHint,
|
|
879
|
+
tokenRefresh: {
|
|
880
|
+
attempted: false,
|
|
881
|
+
success: false,
|
|
882
|
+
errorMessage: `lock acquisition failed: ${msg}`
|
|
883
|
+
}
|
|
884
|
+
};
|
|
885
|
+
}
|
|
763
886
|
return {
|
|
764
887
|
loginStatus: "Refresh Failed",
|
|
765
|
-
hint: "
|
|
888
|
+
hint: "Could not acquire the auth-file lock — too many concurrent `uip` processes, or a permission issue on the auth directory. Retry, or run 'uip login' to re-authenticate.",
|
|
766
889
|
tokenRefresh: {
|
|
767
|
-
attempted:
|
|
890
|
+
attempted: false,
|
|
768
891
|
success: false,
|
|
769
|
-
errorMessage:
|
|
892
|
+
errorMessage: `lock acquisition failed: ${msg}`
|
|
770
893
|
}
|
|
771
894
|
};
|
|
772
895
|
}
|
|
773
|
-
|
|
774
|
-
refreshToken = refreshedRefresh;
|
|
775
|
-
expiration = refreshedExp;
|
|
896
|
+
let lockedFailure;
|
|
776
897
|
try {
|
|
777
|
-
await
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
898
|
+
const outcome = await runRefreshLocked({
|
|
899
|
+
absolutePath,
|
|
900
|
+
refreshToken,
|
|
901
|
+
customAuthority: credentials.UIPATH_URL,
|
|
902
|
+
ensureTokenValidityMinutes,
|
|
903
|
+
loadEnvFile,
|
|
904
|
+
saveEnvFile,
|
|
905
|
+
refreshFn: refreshTokenFn,
|
|
906
|
+
resolveConfig
|
|
784
907
|
});
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
908
|
+
if (outcome.kind === "fail") {
|
|
909
|
+
lockedFailure = outcome.status;
|
|
910
|
+
} else {
|
|
911
|
+
accessToken = outcome.accessToken;
|
|
912
|
+
refreshToken = outcome.refreshToken;
|
|
913
|
+
expiration = outcome.expiration;
|
|
914
|
+
tokenRefresh = outcome.tokenRefresh;
|
|
915
|
+
if (outcome.persistenceWarning) {
|
|
916
|
+
persistenceWarning = outcome.persistenceWarning;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
} finally {
|
|
920
|
+
try {
|
|
921
|
+
await release();
|
|
922
|
+
} catch {
|
|
923
|
+
lockReleaseFailed = true;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
if (lockedFailure) {
|
|
927
|
+
const globalHint = await tryGlobalCredsHint();
|
|
928
|
+
const base = globalHint ? {
|
|
929
|
+
...lockedFailure,
|
|
930
|
+
loginStatus: "Expired",
|
|
931
|
+
hint: globalHint
|
|
932
|
+
} : lockedFailure;
|
|
933
|
+
return lockReleaseFailed ? { ...base, lockReleaseFailed: true } : base;
|
|
797
934
|
}
|
|
798
935
|
}
|
|
799
936
|
const result = {
|
|
@@ -808,23 +945,13 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
|
|
|
808
945
|
expiration,
|
|
809
946
|
source: "file" /* File */,
|
|
810
947
|
...persistenceWarning ? { hint: persistenceWarning, persistenceFailed: true } : {},
|
|
948
|
+
...lockReleaseFailed ? { lockReleaseFailed: true } : {},
|
|
811
949
|
...tokenRefresh ? { tokenRefresh } : {}
|
|
812
950
|
};
|
|
813
951
|
if (result.loginStatus === "Expired") {
|
|
814
|
-
const
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
try {
|
|
818
|
-
const globalCreds = await loadEnvFile({
|
|
819
|
-
envPath: globalPath
|
|
820
|
-
});
|
|
821
|
-
if (globalCreds.UIPATH_ACCESS_TOKEN) {
|
|
822
|
-
const globalExp = getTokenExpiration(globalCreds.UIPATH_ACCESS_TOKEN);
|
|
823
|
-
if (!globalExp || globalExp > new Date) {
|
|
824
|
-
result.hint = `Local credentials file at ${absolutePath} has expired credentials. Valid credentials exist in ${globalPath}. Remove the local file or run 'uip login' to re-authenticate.`;
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
} catch {}
|
|
952
|
+
const globalHint = await tryGlobalCredsHint();
|
|
953
|
+
if (globalHint) {
|
|
954
|
+
result.hint = globalHint;
|
|
828
955
|
}
|
|
829
956
|
}
|
|
830
957
|
return result;
|
|
@@ -841,7 +968,8 @@ var getLoginStatusAsync = async (options = {}) => {
|
|
|
841
968
|
// src/authContext.ts
|
|
842
969
|
var getAuthContext = async (options = {}) => {
|
|
843
970
|
const status = await getLoginStatusAsync({
|
|
844
|
-
ensureTokenValidityMinutes: options.ensureTokenValidityMinutes
|
|
971
|
+
ensureTokenValidityMinutes: options.ensureTokenValidityMinutes,
|
|
972
|
+
envFilePath: options.envFilePath
|
|
845
973
|
});
|
|
846
974
|
if (status.loginStatus !== "Logged in" || !status.baseUrl || !status.accessToken) {
|
|
847
975
|
throw new Error(status.hint ? `Not logged in. ${status.hint}` : "Not logged in. Run 'uip login' first.");
|
|
@@ -868,6 +996,34 @@ var getAuthContext = async (options = {}) => {
|
|
|
868
996
|
tenantName
|
|
869
997
|
};
|
|
870
998
|
};
|
|
999
|
+
var getAuthEnv = async (options = {}) => {
|
|
1000
|
+
const authEnv = {};
|
|
1001
|
+
let status;
|
|
1002
|
+
try {
|
|
1003
|
+
status = await getLoginStatusAsync(options);
|
|
1004
|
+
} catch {
|
|
1005
|
+
return { authEnv };
|
|
1006
|
+
}
|
|
1007
|
+
if (status.loginStatus === "Logged in" && status.accessToken) {
|
|
1008
|
+
authEnv.UIPATH_ACCESS_TOKEN = status.accessToken;
|
|
1009
|
+
if (status.baseUrl) {
|
|
1010
|
+
const org = status.organizationName || status.organizationId;
|
|
1011
|
+
const tenant = status.tenantName || status.tenantId;
|
|
1012
|
+
if (org && tenant) {
|
|
1013
|
+
authEnv.UIPATH_URL = `${status.baseUrl.replace(/\/+$/, "")}/${org}/${tenant}`;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
if (status.organizationId)
|
|
1017
|
+
authEnv.UIPATH_ORGANIZATION_ID = status.organizationId;
|
|
1018
|
+
if (status.organizationName)
|
|
1019
|
+
authEnv.UIPATH_ORGANIZATION_NAME = status.organizationName;
|
|
1020
|
+
if (status.tenantId)
|
|
1021
|
+
authEnv.UIPATH_TENANT_ID = status.tenantId;
|
|
1022
|
+
if (status.tenantName)
|
|
1023
|
+
authEnv.UIPATH_TENANT_NAME = status.tenantName;
|
|
1024
|
+
}
|
|
1025
|
+
return { authEnv, loginStatus: status };
|
|
1026
|
+
};
|
|
871
1027
|
// src/clientCredentials.ts
|
|
872
1028
|
var clientCredentialsLogin = async ({
|
|
873
1029
|
clientId,
|
|
@@ -884,9 +1040,11 @@ var clientCredentialsLogin = async ({
|
|
|
884
1040
|
const params = {
|
|
885
1041
|
grant_type: "client_credentials",
|
|
886
1042
|
client_id: config.clientId,
|
|
887
|
-
client_secret: config.clientSecret ?? ""
|
|
888
|
-
scope: config.scopes.join(" ")
|
|
1043
|
+
client_secret: config.clientSecret ?? ""
|
|
889
1044
|
};
|
|
1045
|
+
if (config.scopes.length > 0) {
|
|
1046
|
+
params.scope = config.scopes.join(" ");
|
|
1047
|
+
}
|
|
890
1048
|
const tokenResponse = await fetch(config.tokenEndpoint, {
|
|
891
1049
|
method: "POST",
|
|
892
1050
|
headers: {
|
|
@@ -933,7 +1091,21 @@ async function logoutWithDeps(options, deps = {}) {
|
|
|
933
1091
|
const fs = getFs();
|
|
934
1092
|
const { absolutePath } = await resolveEnvFilePath(options.file);
|
|
935
1093
|
if (absolutePath && await fs.exists(absolutePath)) {
|
|
936
|
-
|
|
1094
|
+
let release;
|
|
1095
|
+
try {
|
|
1096
|
+
if (typeof fs.acquireLock === "function") {
|
|
1097
|
+
release = await fs.acquireLock(absolutePath);
|
|
1098
|
+
}
|
|
1099
|
+
} catch {
|
|
1100
|
+
release = undefined;
|
|
1101
|
+
}
|
|
1102
|
+
try {
|
|
1103
|
+
await fs.rm(absolutePath);
|
|
1104
|
+
} finally {
|
|
1105
|
+
if (release) {
|
|
1106
|
+
await release().catch(() => {});
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
937
1109
|
return {
|
|
938
1110
|
success: true,
|
|
939
1111
|
message: `Logged out successfully. Removed ${absolutePath}`,
|
|
@@ -981,6 +1153,7 @@ export {
|
|
|
981
1153
|
isBrowser,
|
|
982
1154
|
getLoginStatusWithDeps,
|
|
983
1155
|
getLoginStatusAsync,
|
|
1156
|
+
getAuthEnv,
|
|
984
1157
|
getAuthContext,
|
|
985
1158
|
fetchTenantsAndOrganizations,
|
|
986
1159
|
clientCredentialsLogin,
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export * from "./authContext";
|
|
2
|
+
export * from "./clientCredentials";
|
|
3
|
+
export { type AuthFileConfig, InvalidBaseUrlError, setAuthFileConfig, } from "./config";
|
|
4
|
+
export { ENFORCE_ROBOT_AUTH_VAR, ENV_AUTH_ENABLE_VAR, ENV_AUTH_VARS, EnvAuthConfigError, isEnvAuthEnabled, isRobotAuthEnforced, readAuthFromEnv, } from "./envAuth";
|
|
5
|
+
export * from "./interactive";
|
|
6
|
+
export * from "./loginStatus";
|
|
7
|
+
export * from "./logout";
|
|
8
|
+
export { type SelectFromList, selectTenantWithDeps } from "./selectTenant";
|
|
9
|
+
export { AUTH_TIMEOUT_ERROR_CODE } from "./server";
|
|
10
|
+
export { fetchTenantsAndOrganizations, type Tenant, type TenantsAndOrganizations, } from "./tenantSelection";
|
|
11
|
+
export * from "./tokenRefresh";
|
|
12
|
+
export type { BaseCredentials } from "./types";
|
|
13
|
+
export { DEFAULT_AUTH_FILENAME, DEFAULT_ENV_FILENAME, type EnvFileErrorCode, type EnvFileLocation, type EnvFileSource, type EnvFileUnusable, type EnvFileUnusableReason, loadEnvFileAsync, resolveEnvFileLocationAsync, resolveEnvFilePathAsync, saveEnvFileAsync, } from "./utils/envFile";
|
|
14
|
+
export { parseJWT } from "./utils/jwt";
|
|
15
|
+
export { isBrowser, isNode } from "./utils/platform";
|
|
16
|
+
interface AuthenticateOptions {
|
|
17
|
+
baseUrl?: string;
|
|
18
|
+
clientId?: string;
|
|
19
|
+
clientSecret?: string;
|
|
20
|
+
redirectUri?: URL;
|
|
21
|
+
scope?: string[];
|
|
22
|
+
organization?: string;
|
|
23
|
+
/** Max ms to wait for the browser callback; forwarded to the strategy's
|
|
24
|
+
* local callback server. Defaults to the server's 5-min cap. */
|
|
25
|
+
timeoutMs?: number;
|
|
26
|
+
}
|
|
27
|
+
export declare const authenticate: ({ baseUrl, clientId, clientSecret, redirectUri, scope, organization, timeoutMs, }: AuthenticateOptions) => Promise<{
|
|
28
|
+
accessToken: string;
|
|
29
|
+
refreshToken: string;
|
|
30
|
+
}>;
|