[Self-Service] :: Check Admin Consents
PBIs
#58635 SPIKE: How to check Admin Consent grant?
Context
In order to provide service for a client Empower platform has requirements that have to be fulfilled before any deployment happens. Consenting to AppReg requirements is one of those. Client should provide access to service principals that will work with creating new services in Azure, SSO and Microsoft Graph interaction;
User manuals and Self-serviec UI have links for these consent grant pages re-directing user to Azure. However user might follow the link with no consent granted. There are ways to verify requirements are fulfilled.
Proposed Solution
Steps
- Backend services must be have access to AKV with those SP credentials
- After credentials retrival backend calls Hitachi Solutions MS Graph API
/applications?$filter=appId eq '{required-app-id}'&$select=id,appId,requiredResourceAccessto get information on the required SPs:- Application roles
- Delegated scopes
- Then backend grabs roles & scope definitions
/servicePrincipals?$filter=appId eq '00000003-0000-0000-c000-000000000000'. It is required for mapping role ids to role values (steps 2 and 6) - Since this information is rarely changed, it should be stored in backend's memory cache for it's lifetime and updated once a day
- Backend should try getting JWT from target client's tenant using
scopeparameter with value00000003-0000-0000-c000-000000000000/.defaultwhich stands for MS Graph API - Decoding token provides information on assigned application roles in
rolesclaim - If getting token is not possible then consents are considered to be not granted
- As an extra step to verify roles assigned we can query target's client Graph API to get Graph SP id and get roles assigned to our SPs
/servicePrincipals/{ClientGraphSpId}/appRoleAssignedTo?$filter=principalDisplayName eq '{principalDisplayName}'
Diagrams


Contract considerations
- GET
/api/v1/infra/{tenantId]/consents/returns consent information on all known SPs - GET
/api/v1/infra/{tenantId}/consents/{appRegId}returns consent information on requested SP
[{
"id": "guid",
"name": "string",
"consented": boolean
}]
{
"id": "guid",
"name": "string",
"consented": boolean
}
200 OK: Successful operation
401 Unauthorized: Invalid API key
404 Not Found: Unknown tenant id, unknown app reg id
500 Internal Server Error: couldn't access internal resources (AKV, Hitachi Graph)
MS Graph code examples
// To initialize your graphClient, see https://learn.microsoft.com/en-us/graph/sdks/create-client?from=snippets&tabs=csharp
//
// /servicePrincipals?$filter=appId eq '00000003-0000-0000-c000-000000000000'
//
var result = await graphClient.ServicePrincipals.GetAsync((requestConfiguration) =>
{
requestConfiguration.QueryParameters.Filter = "appId eq '00000003-0000-0000-c000-000000000000'";
});
//
// /applications?$filter=appId eq '{required-app-id}'&$select=id,appId,requiredResourceAccess
//
result = await graphClient.Applications.GetAsync((requestConfiguration) =>
{
requestConfiguration.QueryParameters.Filter = "appId eq '{required-app-id}'";
requestConfiguration.QueryParameters.Select = new string []{ "id","appId","requiredResourceAccess" };
});
//
// /servicePrincipals/{ClientGraphSpId}/appRoleAssignedTo?$filter=principalDisplayName eq '{principalDisplayName}'
//
result = await graphClient.ServicePrincipals["{ClientGraphSpId}"].AppRoleAssignedTo.GetAsync((requestConfiguration) =>
{
requestConfiguration.QueryParameters.Filter = $"principalDisplayName eq '{principalDisplayName}'";
});
# Leverage the power of our client libraries. Download the Python client library here https://aka.ms/msgraphpythonsdk
# To read more about our SDKs, go to the documentation page at https://aka.ms/sdk-doc
from msgraph import GraphServiceClient
from msgraph.generated.service_principals.service_principals_request_builder import ServicePrincipalsRequestBuilder
from kiota_abstractions.base_request_configuration import RequestConfiguration
graph_client = GraphServiceClient(credentials, scopes)
#
# /servicePrincipals?$filter=appId eq '00000003-0000-0000-c000-000000000000'
#
query_params = ServicePrincipalsRequestBuilder.ServicePrincipalsRequestBuilderGetQueryParameters(
filter = "appId eq '00000003-0000-0000-c000-000000000000'",
)
request_configuration = RequestConfiguration(
query_parameters = query_params,
)
result = await graph_client.service_principals.get(request_configuration = request_configuration)
#
#/applications?$filter=appId eq '{required-app-id}'&$select=id,appId,requiredResourceAccess
#
query_params = ApplicationsRequestBuilder.ApplicationsRequestBuilderGetQueryParameters(
filter = "appId eq '{required-app-id}'",
select = ["id","appId","requiredResourceAccess"],
)
request_configuration = RequestConfiguration(
query_parameters = query_params,
)
result = await graph_client.applications.get(request_configuration = request_configuration)
#
# /servicePrincipals/{ClientGraphSpId}/appRoleAssignedTo?$filter=principalDisplayName eq '{principalDisplayName}'
#
query_params = AppRoleAssignedToRequestBuilder.AppRoleAssignedToRequestBuilderGetQueryParameters(
filter = "principalDisplayName eq 'Empower-Yanforov-Test'",
)
request_configuration = RequestConfiguration(
query_parameters = query_params,
)
result = await graph_client.service_principals.by_service_principal_id('servicePrincipal-id').app_role_assigned_to.get(request_configuration = request_configuration)