Forum Discussion
Is it possible to access Dataverse and Microsoft Graph api by single token using AAD auth?
Yes, it is possible to access both Dataverse and Microsoft Graph API using a single token through Azure Active Directory (AAD) authentication. This can be done by configuring the token to have the appropriate scopes or permissions for both resources (Dataverse and Microsoft Graph) under a single Azure AD app registration.
1-You need to register an application in Azure Active Directory (Azure AD)-
Go to Azure Portal > Azure Active Directory > App registrations and create a new app.
2-In the app registration, you need to add API permissions for both Dataverse and Microsoft Graph-
For Dataverse (Power Platform/Dynamics 365), you can add permissions for the "Common Data Service" (CDS) or Dataverse, depending on how it’s labeled in the Azure AD UI.
For Microsoft Graph, you need to add the appropriate Graph API permissions, such as User.Read, Mail.Read, Calendar.Read, etc., depending on what you want to access.
3-OAuth 2.0 Scopes-
Once you’ve added the necessary permissions, you’ll need to request a token that includes both Dataverse and Microsoft Graph scopes.
In the token request, you’ll specify the scopes for both APIs:
For Microsoft Graph, the scopes may look like https://graph.microsoft.com/.default (or specific permissions like User.Read).
For Dataverse, the scopes may look like https://<contoso>.crm.dynamics.com/.default.
4-When requesting the token (using OAuth 2.0, for example), you authenticate against Azure AD, and the resulting token will contain the necessary claims for accessing both Dataverse and Microsoft Graph APIs, provided the correct scopes were included.
5-With the token, you can then make requests to-
Microsoft Graph: Use the token to call Microsoft Graph API endpoints (e.g., https://graph.microsoft.com/v1.0/users).
Dataverse: Use the token to call Dataverse endpoints (e.g., https://<contoso>.crm.dynamics.com/api/data/v9.0).
The app must have the correct permissions for both services in Azure AD.
Ensure the scopes for both Microsoft Graph and Dataverse are included when requesting the token.
The single token will allow you to authenticate and access both services without needing separate authentication flows.
Hi micheleariis
Actually, If I give scope like that way- scope: 'openid profile email offline_access Mail.Send $orgUrl/user_impersonation', then generated toen working for sending mail but not working for dataverse access. Or If I do this way - 'openid profile email offline_access $orgUrl/user_impersonation Mail.Send ' then it's working for dataverse but not for sending mail.
- micheleariisOct 15, 2024MCT
surigaurav179 Got your case 🙂 Azure AD allows you to use one token for only one resource at a time. To access both Microsoft Graph and Dataverse, you will need to request two separate tokens.
- surigaurav179Oct 24, 2024Copper Contributor
Hi micheleariis
When I am trying to make an API call to generate a token then getting CORS issue. Here is the code Future<String?> getAccessToken() async {
final String tenantId =
''; // Your Azure tenant ID
final String clientId =
''; // Your Azure application client ID
final String clientSecret =
''; // Your Azure application client secret
final String scope =
'https://graph.microsoft.com/.default'; // Use .default to request all permissions granted
final String tokenEndpoint =
'https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token';final response = await http.post(
Uri.parse(tokenEndpoint),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Access-Control-Allow-Origin': "https://abc.in/",
'Access-Control-Allow-Credentials': "true",
'Access-Control-Allow-Methods': 'POST,OPTIONS',
'Access-Control-Allow-Headers': 'X-PINGOTHER, Content-Type',
'Access-Control-Max-Age': '86400'
},
body: {
'client_id': clientId,
'client_secret': clientSecret,
'grant_type': 'client_credentials', // Use client credentials flow
'scope': scope,
},
);if (response.statusCode == 200) {
final Map<String, dynamic> tokenResponse = jsonDecode(response.body);
print('tokenResponse==$tokenResponse');
return tokenResponse['access_token'];
} else {
print('Failed to generate token: ${response.body}');
return null;
}
}- micheleariisOct 24, 2024MCTHi, have you considered that to solve the CORS problem and securely obtain access tokens in your Flutter web app, you could avoid using the client credentials flow and include the client secret in the client code? Instead, you could implement the authorization code flow with PKCE using an appropriate authentication library.