AKS Discovery Fails with 401 Unauthorized — Token Audience Mismatch<!-- /*NS Branding Styles*/ --> .ns-kb-css-body-editor-container { p { font-size: 12pt; font-family: Lato; color: var(--now-color--text-primary, #000000); } span { font-size: 12pt; font-family: Lato; color: var(--now-color--text-primary, #000000); } h2 { font-size: 24pt; font-family: Lato; color: var(--now-color--text-primary, black); } h3 { font-size: 18pt; font-family: Lato; color: var(--now-color--text-primary, black); } h4 { font-size: 14pt; font-family: Lato; color: var(--now-color--text-primary, black); } a { font-size: 12pt; font-family: Lato; color: var(--now-color--link-primary, #00718F); } a:hover { font-size: 12pt; color: var(--now-color--link-primary, #024F69); } a:target { font-size: 12pt; color: var(--now-color--link-primary, #032D42); } a:visited { font-size: 12pt; color: var(--now-color--link-primary, #00718f); } ul { font-size: 12pt; font-family: Lato; } li { font-size: 12pt; font-family: Lato; } img { display: ; max-width: ; width: ; height: ; } } KB Article: AKS Discovery Fails with 401 Unauthorized — Token Audience Mismatch FieldValueKB NumberKB2804799CategoryITOM DiscoveryProductDiscovery and Service Mapping PatternsComponentAKSTokenGenerator / AzureApiCommandVersionAll supported versionsArticle TypeProblem/SolutionKeywordsAKS, Kubernetes, Azure, Discovery, 401, Unauthorized, Bearer Token, AAD, Azure AD, Entra ID, Service Principal Problem AKS (Azure Kubernetes Service) discovery fails with the following error: Check your configured Kubernetes credentials. Error Code: 401 Message: Unauthorized Response: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Unauthorized","reason":"Unauthorized","code":401} Discovery uses a Service Principal (Tenant ID, Client ID, and Client Secret) to generate a bearer token from Azure AD. The token is generated successfully, but the AKS Kubernetes API server rejects it with 401 Unauthorized. Cause The 401 error occurs because the bearer token has an incorrect audience (aud) claim. The AKS Kubernetes API server only accepts tokens with the audience set to the Microsoft AKS AAD Server Application ID: 6dae42f8-4368-4678-94ff-3960e28e3630. How Token Audience Works When requesting a token from Azure AD, the resource parameter in the OAuth request determines the aud (audience) field in the issued token. The AKS API server validates this field before processing any request. Correct: resource=6dae42f8-4368-4678-94ff-3960e28e3630 → Token aud = 6dae42f8-4368-4678-94ff-3960e28e3630 → AKS accepts Incorrect: resource=https://management.azure.com/ → Token aud = https://management.azure.com → AKS rejects with 401 Token Comparison Working token (decoded payload): { "aud": "6dae42f8-4368-4678-94ff-3960e28e3630", "iss": "https://sts.windows.net/<tenant-id>/", "appid": "<client-id>", "oid": "<object-id>", "tid": "<tenant-id>", "ver": "1.0" } Non-working token (decoded payload): { "aud": "https://management.azure.com", "iss": "https://sts.windows.net/<tenant-id>/", "appid": "<client-id>", "oid": "<object-id>", "tid": "<tenant-id>", "ver": "1.0" } Both tokens use the same Service Principal credentials. The only difference is the aud field, which is determined by the resource parameter during token generation. Code Reference The AzureApiCommand script include (sys_id: 3f5e2e4cdb071300d504788dbf9619b1) sets the resource parameter in the buildPostClient method: var resource = ''; if(args.isK8s){ resource = "6dae42f8-4368-4678-94ff-3960e28e3630"; // Azure Kubernetes Service AAD Server applicationID } else{ resource = "https://" + this.getResourceName(args, CTX) + "." + this.getAzureUrlBase(args, CTX) + "/"; } If args.isK8s is not true, or if this line has been customized/disabled, the resource defaults to https://management.azure.com/, resulting in a token that AKS will reject. Resolution Step 1: Verify the Code Is Intact Ensure the AzureApiCommand script include has not been modified. The buildPostClient method must set the resource to 6dae42f8-4368-4678-94ff-3960e28e3630 when args.isK8s is true. If this line was disabled or customized, revert it to the out-of-box version. Step 2: Verify AKS Azure AD Integration Is Enabled The AKS cluster must have Azure AD authentication enabled. Run: az aks show --name <cluster-name> --resource-group <resource-group> --query "aadProfile" Expected output: { "adminGroupObjectIDs": ["..."], "enableAzureRbac": true, "managed": true, "tenantId": "<tenant-id>" } If aadProfile is null, Azure AD is not enabled. Enable it: az aks update \ --resource-group <resource-group> \ --name <cluster-name> \ --enable-aad \ --aad-admin-group-object-ids <admin-group-object-id> Step 3: Create a Service Principal (If Not Already Created) az ad sp create-for-rbac --name "ServiceNow-AKS-Discovery" --skip-assignment Output: { "appId": "<client-id>", "displayName": "ServiceNow-AKS-Discovery", "password": "<client-secret>", "tenant": "<tenant-id>" } Use these values to configure the Azure credential in ServiceNow. Step 4: Grant the Service Principal Access to the AKS Cluster Option A — If Azure RBAC for Kubernetes is enabled: az role assignment create \ --assignee <client-id> \ --role "Azure Kubernetes Service RBAC Reader" \ --scope /subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.ContainerService/managedClusters/<cluster-name> az role assignment create \ --assignee <client-id> \ --role "Reader" \ --scope /subscriptions/<sub-id> Option B — If using Kubernetes RBAC: az aks get-credentials --name <cluster-name> --resource-group <rg> --admin SP_OBJECT_ID=$(az ad sp show --id <client-id> --query id -o tsv) kubectl create clusterrolebinding servicenow-discovery \ --clusterrole=cluster-admin \ --user=${SP_OBJECT_ID} Step 5: Configure Credentials in ServiceNow Navigate to Discovery CredentialsCreate a new Azure credentialEnter: Client ID: <appId> from Step 3Client Secret: <password> from Step 3Tenant ID: <tenant> from Step 3 Associate the credential with the Service Account used for AKS discovery Step 6: Validate Token Generation Run the following command to verify a correct token is generated: curl -s -X POST \ "https://login.microsoftonline.com/<tenant-id>/oauth2/token" \ -d "grant_type=client_credentials" \ Verify the decoded token has the correct audience: TOKEN=$(curl -s -X POST \ "https://login.microsoftonline.com/<tenant-id>/oauth2/token" \ -d "grant_type=client_credentials" \ -d "client_id=<client-id>" \ -d "client_secret=<client-secret>" \ -d "resource=6dae42f8-4368-4678-94ff-3960e28e3630" \ | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])") echo "$TOKEN" | cut -d. -f2 | python3 -c " import sys, base64, json data = sys.stdin.read().strip() data += '=' * (-len(data) % 4) payload = json.loads(base64.urlsafe_b64decode(data)) print(json.dumps(payload, indent=2)) " Confirm "aud": "6dae42f8-4368-4678-94ff-3960e28e3630" in the output. Verification Checklist CheckCommandExpectedAKS AAD enabledaz aks show -n <name> -g <rg> --query "aadProfile.managed"trueSP existsaz ad sp show --id <client-id>Returns SP detailsSP has cluster RBACaz role assignment list --assignee <client-id> --scope <aks-resource-id>Shows role assignmentToken audience correctDecode token and check aud field6dae42f8-4368-4678-94ff-3960e28e3630AKS API accessiblecurl -sk -H "Authorization: Bearer $TOKEN" <aks-api>/api/v1/namespacesReturns namespace listCredentials in ServiceNowCheck Discovery CredentialsClient ID, Secret, Tenant ID configured Related Information AKSTokenGenerator script include: sys_id: 441e980687ea85506a5299b83cbb356bAzureApiCommand script include: sys_id: 3f5e2e4cdb071300d504788dbf9619b1Microsoft AKS AAD Server Application ID: 6dae42f8-4368-4678-94ff-3960e28e3630 (globally managed by Microsoft)MID Server property for custom AAD App ID: sn_itom_pattern.aks_aad_server_app_id (only needed for legacy custom AAD server applications)Azure Documentation: AKS-managed Azure Active Directory integrationOlder version KB1220553