@@ -396,7 +396,14 @@ api.ajax.jsonrpc = {};
396
396
* @param {* } pItemSpinner
397
397
* @param {* } pHideSuccessErrorModal
398
398
*/
399
+
399
400
api . ajax . jsonrpc . request = function ( pAPI_URL , pAPI_Method , pAPI_Params , callbackFunctionName_onSuccess , callbackParams_onSuccess , callbackFunctionName_onError , callbackParams_onError , pAJAX_Params , pItemSpinner = null , pHideSuccessErrorModal = false ) {
401
+ //call the async function to handle catch block of acquiretokensilently
402
+ api . ajax . jsonrpc . processRequestAsync ( pAPI_URL , pAPI_Method , pAPI_Params , callbackFunctionName_onSuccess , callbackParams_onSuccess , callbackFunctionName_onError , callbackParams_onError , pAJAX_Params , pItemSpinner , pHideSuccessErrorModal )
403
+ }
404
+
405
+
406
+ api . ajax . jsonrpc . processRequestAsync = async function ( pAPI_URL , pAPI_Method , pAPI_Params , callbackFunctionName_onSuccess , callbackParams_onSuccess , callbackFunctionName_onError , callbackParams_onError , pAJAX_Params , pItemSpinner = null , pHideSuccessErrorModal = false ) {
400
407
// Default API parameters
401
408
pAPI_Params = pAPI_Params || { } ;
402
409
@@ -430,6 +437,7 @@ api.ajax.jsonrpc.request = function (pAPI_URL, pAPI_Method, pAPI_Params, callbac
430
437
"id" : callID
431
438
} ;
432
439
440
+
433
441
// Extend AJAX Parameters
434
442
var extendedAJAXParams = {
435
443
url : pAPI_URL ,
@@ -511,10 +519,24 @@ api.ajax.jsonrpc.request = function (pAPI_URL, pAPI_Method, pAPI_Params, callbac
511
519
}
512
520
}
513
521
514
- // Merge pAJAX_Params into extendedAJAXParams
515
- $ . extend ( extendedAJAXParams , pAJAX_Params ) ;
522
+
523
+ let headers = pAJAX_Params . headers || { } ;
524
+
516
525
517
526
try {
527
+ //force to wait for return
528
+ const token = await api . sso . acquireAccessTokenSilently ( pAPI_Method ) ;
529
+
530
+ if ( token ) {
531
+ headers [ "MSAL" ] = `Bearer ${ token } ` ;
532
+ }
533
+
534
+ // Inject headers into AJAX params
535
+ extendedAJAXParams . headers = headers ;
536
+
537
+ // Merge pAJAX_Params after injecting headers to avoid overwrite
538
+ $ . extend ( true , extendedAJAXParams , pAJAX_Params ) ;
539
+
518
540
// Start the nav loader
519
541
$ ( "#nav-loader" ) . removeClass ( 'invisible' ) ;
520
542
$ ( "body" ) . css ( "cursor" , "progress" ) ;
@@ -528,7 +550,7 @@ api.ajax.jsonrpc.request = function (pAPI_URL, pAPI_Method, pAPI_Params, callbac
528
550
// Make the Ajax call
529
551
return $ . ajax ( extendedAJAXParams ) ;
530
552
} catch ( error ) {
531
- console . log ( error )
553
+ console . log ( error ) ;
532
554
// Pop the exception in the Bootstrap Modal
533
555
api . modal . exception ( "An unhandled Ajax exception has occurred. Please try again." ) ;
534
556
return false ;
@@ -1058,4 +1080,226 @@ api.cookie.session.intervalRoutine = function () {
1058
1080
} else {
1059
1081
// The session is valid, do nothing
1060
1082
}
1061
- } ;
1083
+ } ;
1084
+
1085
+
1086
+ /*******************************************************************************
1087
+ API - Library - Single Sign On
1088
+ *******************************************************************************/
1089
+ api . sso = { } ;
1090
+ api . sso . msalConfigObj = { } ;
1091
+ api . sso . msalInstance = null ;
1092
+ api . sso . tokenPromise = null ;
1093
+
1094
+ //temporary, to be removed
1095
+ api . sso . response = null ;
1096
+
1097
+ api . sso . authenticateUserSilently = function ( callbackFunctionName_onSuccess , callbackFunctionName_onError , hideLoginPopup ) {
1098
+ api . spinner . start ( ) ;
1099
+
1100
+ hideLoginPopup = hideLoginPopup || false ;
1101
+
1102
+ let loginRequest = {
1103
+ scopes : [ "api://" + api . sso . msalConfigObj . auth . clientId + "/access_application" ]
1104
+ } ;
1105
+
1106
+ api . sso . msalInstance . ssoSilent ( loginRequest ) . then ( ( response ) => {
1107
+ api . spinner . stop ( ) ;
1108
+ //User logged in successfully
1109
+
1110
+ console . log ( response . accessToken )
1111
+ /* console.log("expiresOn : " + response.expiresOn);
1112
+ console.log("extExpiresOn : " + response.extExpiresOn);
1113
+ console.log("FIRST");
1114
+ */
1115
+
1116
+ api . sso . response = response ;
1117
+
1118
+
1119
+ api . ajax . callback ( callbackFunctionName_onSuccess , response ) ;
1120
+ } ) . catch ( error => {
1121
+ api . spinner . stop ( ) ;
1122
+ console . log ( "Silent Error: " + error ) ;
1123
+
1124
+ if ( hideLoginPopup ) {
1125
+ //Error during login
1126
+ if ( callbackFunctionName_onError != null ) {
1127
+ api . ajax . callback ( callbackFunctionName_onError , error ) ;
1128
+ }
1129
+ } else if ( error instanceof msal . InteractionRequiredAuthError ) {
1130
+ //if the error indicates interaction is required, fallback to login
1131
+ console . log ( "SSO Silent requires interation. prompting login...." )
1132
+ api . sso . authenticateUserPopup ( callbackFunctionName_onSuccess , callbackFunctionName_onError ) ;
1133
+ } else {
1134
+ //Error during login
1135
+ if ( callbackFunctionName_onError != null ) {
1136
+ api . ajax . callback ( callbackFunctionName_onError , error ) ;
1137
+ }
1138
+ }
1139
+ } ) ;
1140
+ } ;
1141
+
1142
+
1143
+ /**
1144
+ * call to entra ID to authenticate the user with popup
1145
+ * @param {* } callbackFunctionName_onSuccess
1146
+ * @param {* } callbackFunctionName_onError
1147
+ */
1148
+ api . sso . authenticateUserPopup = function ( callbackFunctionName_onSuccess , callbackFunctionName_onError ) {
1149
+ console . log ( "authenticateUserPopup" ) ;
1150
+ let loginRequest = {
1151
+ scopes : [ "api://" + api . sso . msalConfigObj . auth . clientId + "/access_application" ]
1152
+ } ;
1153
+ api . spinner . start ( ) ;
1154
+ api . sso . msalInstance . loginPopup ( loginRequest )
1155
+ . then ( ( response ) => {
1156
+ //User logged in successfully
1157
+ api . spinner . stop ( ) ;
1158
+ console . log ( response . accessToken )
1159
+ //// api.idle.startIdleTimer();
1160
+ api . ajax . callback ( callbackFunctionName_onSuccess , response ) ;
1161
+ } )
1162
+ . catch ( error => {
1163
+ api . spinner . stop ( ) ;
1164
+ console . log ( "login failed:" , error ) ;
1165
+ //Error during login
1166
+ api . ajax . callback ( callbackFunctionName_onError , error ) ;
1167
+ } ) ;
1168
+ }
1169
+
1170
+ /**
1171
+ * call to entra ID to authenticate the user with popup
1172
+ * @param {* } callbackFunctionName_onSuccess
1173
+ * @param {* } callbackFunctionName_onError
1174
+ */
1175
+ api . sso . authenticateUserPopupAsync = async function ( ) {
1176
+ console . log ( "authenticateUserPopup" ) ;
1177
+ let loginRequest = {
1178
+ scopes : [ "api://" + api . sso . msalConfigObj . auth . clientId + "/access_application" ]
1179
+ } ;
1180
+
1181
+ try {
1182
+ return await api . sso . msalInstance . loginPopup ( loginRequest ) ;
1183
+ } catch ( error ) {
1184
+ console . log ( "login failed:" , error ) ;
1185
+ // Error during login
1186
+ return null ;
1187
+ }
1188
+
1189
+ }
1190
+
1191
+ /**
1192
+ * call to entra ID to logout the user with popup
1193
+ * @param {* } callbackFunctionName_onSuccess
1194
+ * @param {* } callbackFunctionName_onError
1195
+ */
1196
+ api . sso . logout = function ( callbackFunctionName_onSuccess , callbackFunctionName_onError ) {
1197
+ // Default callback functions
1198
+ callbackFunctionName_onSuccess = callbackFunctionName_onSuccess || null ;
1199
+ callbackFunctionName_onError = callbackFunctionName_onError || null ;
1200
+ // you can select which account application should sign out
1201
+ const logoutRequest = {
1202
+ account : api . sso . getMsalAccount ( )
1203
+ } ;
1204
+ api . sso . msalInstance . logoutPopup ( logoutRequest )
1205
+ . then ( ( ) => {
1206
+ if ( callbackFunctionName_onSuccess ) {
1207
+ api . ajax . callback ( callbackFunctionName_onSuccess ) ;
1208
+ }
1209
+
1210
+ } )
1211
+ . catch ( ( error ) => {
1212
+ if ( callbackFunctionName_onError ) {
1213
+ api . ajax . callback ( callbackFunctionName_onError , error ) ;
1214
+ }
1215
+ } ) ;
1216
+ } ;
1217
+
1218
+
1219
+ /**
1220
+ * check if the user has an entra account and retrieve token if present
1221
+ * @param {* } pAPI_Method
1222
+ */
1223
+ api . sso . acquireAccessTokenSilently = function ( pAPI_Method ) {
1224
+
1225
+ console . log ( "get access token silently" ) ;
1226
+
1227
+ const validAccount = api . sso . getMsalAccount ( ) ;
1228
+
1229
+ if ( validAccount ) {
1230
+ // Set the first account as the active account
1231
+ api . sso . msalInstance . setActiveAccount ( validAccount ) ;
1232
+ } else {
1233
+ // Handle the case where no account is signed in
1234
+ return null ; // Promise.reject("No account signed in");
1235
+ }
1236
+
1237
+ console . log ( api . sso . tokenPromise ) ;
1238
+
1239
+ // If token request is already in progress, reuse it
1240
+ if ( api . sso . tokenPromise ) return api . sso . tokenPromise ;
1241
+
1242
+ let scope = [ "api://" + api . sso . msalConfigObj . auth . clientId + "/access_application" ] ;
1243
+
1244
+ /***
1245
+ *
1246
+ *
1247
+ *
1248
+ * to test the catch block
1249
+ * api.sso.tokenPromise = Promise.reject(new msal.InteractionRequiredAuthError("Simulated error"))
1250
+ *
1251
+ *
1252
+ */
1253
+
1254
+ api . sso . tokenPromise = api . sso . msalInstance . acquireTokenSilent ( {
1255
+ scopes : scope ,
1256
+ account : api . sso . msalInstance . getActiveAccount ( ) ,
1257
+ forceRefresh : true
1258
+ } ) . then ( ( response ) => {
1259
+ // User is authenticated, return access token
1260
+ api . sso . tokenPromise = null ; // clear cache
1261
+ console . log ( response . expiresOn ) ;
1262
+ console . log ( "finished2 =>" + pAPI_Method ) ;
1263
+
1264
+ return response . accessToken ;
1265
+ } ) . catch ( async ( error ) => {
1266
+ if ( error instanceof msal . InteractionRequiredAuthError ) {
1267
+ const response = await api . sso . authenticateUserPopupAsync ( ) ;
1268
+ api . sso . tokenPromise = null ;
1269
+ if ( response . accessToken ) {
1270
+ return response . accessToken ;
1271
+ } else {
1272
+ return null
1273
+ }
1274
+ } else {
1275
+ api . sso . tokenPromise = null ;
1276
+ return null
1277
+ }
1278
+ } ) ;
1279
+
1280
+ console . log ( "finished1 =>" + pAPI_Method ) ;
1281
+ return api . sso . tokenPromise ;
1282
+ }
1283
+
1284
+ /**
1285
+ *
1286
+ *
1287
+ * gets msalAccount for the application
1288
+ */
1289
+ api . sso . getMsalAccount = function ( ) {
1290
+
1291
+ if ( api . sso . msalInstance == null ) {
1292
+ return null ;
1293
+ }
1294
+
1295
+ // Get all accounts
1296
+ const accounts = api . sso . msalInstance . getAllAccounts ( ) ;
1297
+
1298
+ //get the valid account
1299
+ const validAccount = accounts . find ( account => {
1300
+ const idTokenClaims = account . idTokenClaims ;
1301
+ return idTokenClaims && idTokenClaims . aud === api . sso . msalConfigObj . auth . clientId ;
1302
+ } ) ;
1303
+
1304
+ return validAccount ;
1305
+ }
0 commit comments