Access Token validation for OAuth configured with Microsoft Identity PlatformOverview The final step of Configuring SMTP and/or IMAP email accounts using Microsoft Identity Platform OAuth Flow is to obtain the access and refresh tokens using Authorize Email Account Access UI Action. After receiving the respective tokens and confirming that Test Connection is successful, the email receiving/sending is expected to work. However, sometimes this might not be the case and there is no apparent error received that helps us to diagnose the issue. TL;DR: Use the provided Scripts - Background to validate the received Access Token. It has been observed that the issue is more commonly attributed to the wrong Microsoft account authorizing the Email account access. For example, when a user is logged into the ServiceNow instance using Microsoft SSO or already has a Microsoft session running in the same browser (e.g., Outlook or Office), the active session will automatically be picked up by the browser when the Authorize Email Account Access UI Action is invoked. As a result, the user's own account is used to authorize the email account access instead of the intended IMAP/SMTP account. For example, the following Email Account is configured to use servicedesk@vbcpn.onmicrosoft.com Microsoft account as an IMAP mailbox: The logged-in user AdeleV@vbcpn.onmicrosoft.com is an SSO user. Hence, when the user Adele Vance tries to authorize email account access for the above IMAP account by clicking UI Action Authorize Email Account Access, Microsoft uses Adele's active session in the browser. This effectively prevents email retrievable from the IMAP account servicedesk@vbcpn.onmicrosoft.com since the tokens received are for the account authorizing the access, i.e. AdeleV@vbcpn.onmicrosoft.com For this reason, it is recommended to strictly adhere to Step 6. of KB0816072: You must use an incognito/private window and a local login (side_door.do if needed) to make sure your personal account is not picked up by Microsoft SSO login. The username/credentials of the email account should be provided, not your own credentials. If you try to authorize while you are already logged in to Azure, no pop-up window will appear and it might look like the authorization succeeded. However, the instance will receive an access token for your own credentials instead of the email account. Ideally, you should be getting the Microsoft Sign in prompt where you specify the email address of the Email Account: You can use the Scripts - Background provided below to validate the received Access Token. Scripts - Background The following Scripts - Background validates the Access Token for OAuth configured with Microsoft Identity Platform for Email Integration. If the validation fails, the solution is proposed in the Next Steps of the output. Instructions From the Navigator Menu, go to All > System Definition > Scripts - BackgroundCopy and paste the script provided belowSpecify the sys_id of the Email Account e.g. var email_account = "d94b4a7b3b78a210378b9d1d16e45a67"; Run Script in global scope. // ====== [ Access Token validation for OAuth configured with Microsoft Identity Platform ] ====== // Note: Run in Global Scope // Related KB: KB2071947 // Specify SysID of the Email Account var email_account = "__SYS_ID__"; //sys_id of [sys_email_account] /** =================================== // DO NOT EDIT BELOW THIS LINE // =================================== */ // Glide Records var email_gr = new GlideRecord("sys_email_account"); var oauth_cred = getAccessToken(); var instance_name = gs.getProperty("glide.servlet.uri"); var output_string = "\n\r======================================================================================\n" + "Access Token validation for OAuth configured with Microsoft Identity Platform\n" + "--------------------------------------------------------------------------------------\n\r"; if (email_gr.get(email_account)) { var email_user = email_gr.getValue("user_name"); var email_type = email_gr.getValue("type").toUpperCase(); var authorization_instruction = '!!!IMPORTANT!!! - Make sure you provide the credential for the Microsoft Account "' + email_user + '" during the authorization process. It is recommended to use incognito mode and login as a local admin user so that you do not already have an active Microsoft session in the browser. Ideally you should receive Microsoft prompt to put in the credential and grant the authorization for the account "' + email_user + '"'; if (oauth_cred) { var decrypted_token = parseJwt(oauth_cred.gr.token_received.getDecryptedValue()); //gs.print(JSON.stringify(decrypted_token)); var oauth_app_gr = new GlideRecord("oauth_entity"); oauth_app_gr.get(oauth_cred.gr.getValue("peer")); var scopes = decrypted_token.scp.split(" "); // output_string += 'Email Account:\t"' + email_gr.getValue("name") + '"\n'; output_string += '\tUser name:\t' + email_user + '\n'; output_string += '\tType:\t\t' + email_type + '\n'; output_string += '\tAuthentication:\t' + email_gr.getValue("authentication") + '\n'; output_string += '\tLink:\t\t' + instance_name + 'sys_email_account.do?sys_id=' + email_account + '\n\r\n\r'; output_string += 'Access Token:\n'; output_string += '\tIssued on:\t' + new Date(decrypted_token.iat * 1000) + '\n'; output_string += '\tExpires on:\t' + new Date(decrypted_token.exp * 1000) + '\n'; output_string += '\tUPN:\t\t' + decrypted_token.upn + '\n'; output_string += '\tName:\t\t' + decrypted_token.name + '\n'; output_string += '\tID Type:\t' + decrypted_token.idtyp + '\n'; output_string += '\tScopes:\t\t' + scopes.join(", ") + '\n'; output_string += '\tAudience:\t' + decrypted_token.aud + '\n'; output_string += '\tLink:\t\t' + instance_name + 'oauth_credential.do?sys_id=' + oauth_cred.gr.getValue("sys_id") + '\n'; output_string += '\tOAuth App:\t"' + oauth_app_gr.getValue("name") + '":\n'; output_string += '\t\t\t' + instance_name + 'oauth_entity.do?sys_id=' + oauth_app_gr.getValue("sys_id") + '\n\r\n\r'; if (email_user === decrypted_token.upn) { output_string += 'SUCCESS:\tCongratulations! ' + email_type + ' Email Account "' + email_gr.getValue("name") + '" is configured correctly.\n\t\tUser name "' + email_user + '" matches UPN "' + decrypted_token.upn + '" in the token.\n'; } else { output_string += 'ERROR:\t' + email_type + ' Email Account "' + email_gr.getValue("name") + '" with User name "' + email_user + '" DOES NOT match UPN "' + decrypted_token.upn + '" in the token.\n'; output_string += '\tPlease re-authorize using the Microsoft account "' + email_user + '".\n\r'; output_string += "Next Steps:\n" output_string += "\t1.\tDelete following tokens:\n\t\t" + instance_name + "oauth_credential_list.do?requestor_id=" + oauth_cred.requestor_profile + "\n\r"; output_string += '\t2.\tGet fresh pair of tokens for Email Account "' + email_gr.getValue("name") + '" by using UI Action "Authorize Email Account Access" under Related Links:\n'; output_string += '\t\t' + instance_name + 'sys_email_account.do?sys_id=' + email_account + '\n\r'; output_string += '\t\t' + authorization_instruction + '\n\r'; output_string += "\t3.\tRun this script again to make sure the correct tokens are received. Once confirmed, email should be working as expected.\n\r"; } } else { output_string += "ERROR: \tAccess token is not found. Please authorize Email account to receive the tokens.\n\r"; output_string += '\t'+authorization_instruction + '\n\r'; } } else { output_string += "ERROR:\tEmail account with sys_id " + email_account + " is not found. Please provide a valid sys_id.\n\r"; } // Output gs.print(output_string); // Helpers /** * Returns JWT Token JSON Payload * @param {string} token - Decrypted JWT Token String */ function parseJwt (token) { var base64Url = token.split('.')[1]; var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); var jsonPayload = decodeURIComponent(GlideStringUtil.base64Decode(base64).split('').map(function(c) { return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); }).join('')); return JSON.parse(jsonPayload); } /** * Returns an object with OAuth Credential Record and Requestor Profile Sys_ID */ function getAccessToken () { var reqProf_gr = new GlideRecord("oauth_requestor_profile"); reqProf_gr.addQuery("requestor_id", email_account); reqProf_gr.query(); if (reqProf_gr.next()) { var oauth_cred_gr = new GlideRecord("oauth_credential"); oauth_cred_gr.addQuery("oauth_requestor_profile", reqProf_gr.getValue("sys_id")); oauth_cred_gr.addQuery("type", "access_token"); oauth_cred_gr.orderByDesc("sys_updated_on"); oauth_cred_gr.setLimit(1); oauth_cred_gr.query(); if (oauth_cred_gr.next()) { return { gr: oauth_cred_gr, requestor_profile: reqProf_gr.getValue("sys_id") } ; } else { return; } } return; } Outputs The script decodes the JWT (Access Token) received from Microsoft and checks it against the email account's User name. 1. Example - Invalid Token ====================================================================================== Access Token validation for OAuth configured with Microsoft Identity Platform -------------------------------------------------------------------------------------- Email Account: "Microsoft Azure IMAP" User name: servicedesk@vbcpn.onmicrosoft.com Type: IMAP Authentication: oauth2 Link: https://emp.service-now.com/sys_email_account.do?sys_id=d94b4a7b3b78a210378b9d1d16e45a67 Access Token: Issued on: Thu Apr 17 2025 22:25:09 GMT-0700 (PDT) Expires on: Thu Apr 17 2025 23:32:46 GMT-0700 (PDT) UPN: AdeleV@vbcpn.onmicrosoft.com Name: Adele Vance ID Type: user Scopes: IMAP.AccessAsUser.All, SMTP.Send Audience: https://outlook.office.com Link: https://emp.service-now.com/oauth_credential.do?sys_id=cd2064a82b096610c286f216d891bfd2 OAuth App: "Microsoft Azure Mail": https://emp.service-now.com/oauth_entity.do?sys_id=9ff60a373b78a210378b9d1d16e45a00 ERROR: IMAP Email Account "Microsoft Azure IMAP" with User name "servicedesk@vbcpn.onmicrosoft.com" DOES NOT match UPN "AdeleV@vbcpn.onmicrosoft.com" in the token. Please re-authorize using the Microsoft account "servicedesk@vbcpn.onmicrosoft.com". Next Steps: 1. Delete following tokens: https://emp.service-now.com/oauth_credential_list.do?requestor_id=78e0bd4c2bc9e210c286f216d891bff7 2. Get fresh pair of tokens for Email Account "Microsoft Azure IMAP" by using UI Action "Authorize Email Account Access" under Related Links: https://emp.service-now.com/sys_email_account.do?sys_id=d94b4a7b3b78a210378b9d1d16e45a67 !!!IMPORTANT!!! - Make sure you provide the credential for the Microsoft Account "servicedesk@vbcpn.onmicrosoft.com" during the authorization process. It is recommended to use incognito mode and login as a local admin user so that you do not already have an active Microsoft session in the browser. Ideally you should receive Microsoft prompt to put in the credential and grant the authorization for the account "servicedesk@vbcpn.onmicrosoft.com" 3. Run this script again to make sure the correct tokens are received. Once confirmed, email should be working as expected. 2. Example - Valid Token ====================================================================================== Access Token validation for OAuth configured with Microsoft Identity Platform -------------------------------------------------------------------------------------- Email Account: "Microsoft Azure IMAP" User name: servicedesk@vbcpn.onmicrosoft.com Type: IMAP Authentication: oauth2 Link: https://emp.service-now.com/sys_email_account.do?sys_id=d94b4a7b3b78a210378b9d1d16e45a67 Access Token: Issued on: Thu Apr 17 2025 22:51:32 GMT-0700 (PDT) Expires on: Fri Apr 18 2025 00:09:56 GMT-0700 (PDT) UPN: servicedesk@vbcpn.onmicrosoft.com Name: Service Desk ID Type: user Scopes: IMAP.AccessAsUser.All, SMTP.Send Audience: https://outlook.office.com Link: https://emp.service-now.com/oauth_credential.do?sys_id=53266c202b496610c286f216d891bfa8 OAuth App: "Microsoft Azure Mail": https://emp.service-now.com/oauth_entity.do?sys_id=9ff60a373b78a210378b9d1d16e45a00 SUCCESS: Congratulations! IMAP Email Account "Microsoft Azure IMAP" is configured correctly. User name "servicedesk@vbcpn.onmicrosoft.com" matches UPN "servicedesk@vbcpn.onmicrosoft.com" in the token.