Trying to build a client-side app using the Microsoft Graph Security API.
We've made the grants in the Azure Portal, granted Admin Consent, and the JWT is showing the scopes are present (snippet below):
"scp": "Calendars.Read MailboxSettings.Read offline_access People.Read profile SecurityEvents.Read.All SecurityEvents.ReadWrite.All User.Read User.Read.All",
Here's how we're requesting the token:
// acquire token for ms graph. the service we're acquiring a token for
// should be the same service we call in the ajax request below
authContext.acquireToken('https://graph.microsoft.com', (error, token) => {
// Handle ADAL Error
if (error || !token) {
printErrorMessage('ADAL Error Occurred: ' + error);
return;
}
this.token = token; //update our data with the token
});
But when we hit the endpoint with a web call, we're still getting a 403 with no data returned:
$.ajax({
type: "GET",
url: "https://graph.microsoft.com/v1.0/security/alerts",
headers: {
'Authorization': 'Bearer ' + this.token,
}
}).done(async (data) => {
console.log(data);
}).fail(() => {
console.log('Error getting top 10 people!');
});
And here's the underlying error (via Postman):
{
"error": {
"code": "UnknownError",
"message": "Auth token does not contain valid permissions or user does not have valid roles.",
"innerError": {
"request-id": "6411dbc9-eebb-4522-b789-62ab5f754d0c",
"date": "2019-04-23T15:17:12"
}
}
}
Edit: The user accessing the app has the "Security reader" Directory role attached.
Any assistance would be GREATLY appreciated. :)
It looks like your app has the correct scopes, but the user that is requesting alerts from the Microsoft Graph Security API does not have a Security reader role in Azure AD.
To add roles to users, sign in to Azure portal as the tenant admin then select the Azure Active Directory blade > Users > select the name of the user > Directory Role > and then select Add role.
Once the user has access to read security information, they should be able to receive alerts through the Microsoft Graph Security API.
Source: https://learn.microsoft.com/graph/security-authorization#assign-azure-ad-roles-to-users
I’ve been working behind-the-scenes with some MS DEV resources, and we believe we’ve tracked down why this doesn’t work.
Taken from an email:
The implicit grant in through AAD uses response_mode=fragment by default. Once the response mode is changed to response_mode=form_post the id token ,and access token if requested, are sent as a POST request and contain the wids claim which allows the Graph API security endpoints to be used.
The workaround proposed there was to basically build a server-side app that would catch the POST request that would have the roles, then use that to call the Graph Security API.
This works, but basically means implicit flow client side apps are essentially incompatible with the Graph Secuirty API. Super frustrating and extremely difficult to track down from the documentation.
Hopefully there is some other mechanism MS can come up with.
Related
I am building an angular web application using ADAL.js that accesses other Azure APIs and I am successful in accessing custom web API, Power BI API, and the Graph API. Unfortunately I am unable to access the Azure Data Catalog, I am acquiring the token like all the other services by requesting by resource URI. I have added the users and the app service principal name as Catalog Users and the app registration has Azure Data Catalog delegated access. Below is the code that I use to get the token and then I attach it to the header like I do for the other APIs. This is the only Azure API I have had problems accessing. Thanks in advance if anyone is able to help.
var token = authContext.acquireToken('https://api.azuredatacatalog.com')
If you want to call the Azure Data Catalog rest api with adad.js, please refer to the following steps
Register an Azure AD application
Configure permissions
Code
var resource ="https://api.azuredatacatalog.com"
authContext.acquireToken(resource, function (error, token) {
// Handle ADAL Error
if (error || !token) {
printErrorMessage('ADAL Error Occurred: ' + error);
return;
}
// Get TodoList Data
$.ajax({
type: "GET",
url: "https://api.azuredatacatalog.com/catalogs/{catalog_name}/search/search?api-version={api-version}&searchTerms={search_terms}",
headers: {
'Authorization': 'Bearer ' + token,
},
});
I'm integrating my smarthome services on the Actions on Google platform and I have some problems during the authentication process.
I have an Amazon Cognito user pool configured that I'm using for authentication, and apparently works fine, but I never receive the token on any request sent from Google to my back-end services.
The official documentation says the following:
"When you have authenticated a user, the user's third-party OAuth 2 access token is sent in the Authorization header when smart home intents are sent to your fulfillment."
But in fact, I don't receive that token.
{
"inputs": {
"0": {
"intent": "action.devices.SYNC"
}
},
"requestId": "7597788060327530693"
}
My account linking configuration:
https://i.stack.imgur.com/hLaVN.png
What you've posted is the request body. The headers should exist as a separate object in your request, which will be a key-value pair of metadata. One datum should be Authorization.
I successfully set up OAuth 2.0 client credentials for Microsoft Graph, I am getting the auth token no problem, subscribed to receive email webhooks for several users, and getting those email notifications.
In Azure Portal, I set up the application to have Microsoft Graph app level permissions for "Send mail as any user".
I am trying to forward an email using Graph, but I get a BadRequest error:
{
"error": {
"code": "BadRequest",
"message":
"Current authenticated context is not valid for this request. This occurs when a request is made to an endpoint that requires user sign-in. For example, /me requires a signed-in user. Acquire a token on behalf of a user to make requests to these endpoints. Use the OAuth 2.0 authorization code flow for mobile and native apps and the OAuth 2.0 implicit flow for single-page web apps.",
"innerError": {
"request-id": "a64c4533-9389-4284-8cf5-68fcadf21832",
"date": "2018-05-27T17:34:29"
}
}
}
This is how I'm sending the request:
postData(
`${graphVersion}/me/messages/${req.body.emailUid}/forward`,
global.accessToken,
JSON.stringify(forwardConfiguration),
(requestError, data) => {
if (requestError) {
logger.log('error', "Failed to forward email: " + JSON.stringify(requestError));
} else {
logger.log("info", "Successfully forwarded email from " + req.body.email);
}
}
);
You cannot use /me with Client Credentials.
This is because /me is simply an alias for /user/{currentUser}. When you use Client Credentials, there isn't a "user" for the API to map this alias too.
You need to explicitly specify the user you want:
/users/{userId or userPrincipalName}/messages
I'm using the adal-angular library (but not with Angular) in my SPA to try to acquire an access token that I can use to call the SharePoint APIs (https://<my-tenant>.sharepoint.com/_api/).
I've registered an application in Azure AD and enabled the implicit flow in the manifest, and I'm now running my SPA locally, which is why there's a localhost redirect URI. The code below is being executed on startup:
const context = new AuthenticationContext({
clientId: '<my-client-id>',
redirectUri: 'http://localhost:3000/signin',
popUp: true,
loginResource: 'https://<my-tenant>.sharepoint.com',
callback: () => window.location.reload()
});
const user = context.getCachedUser();
if (!user) {
context.login();
} else {
context.acquireToken('https://<my-tenant>.sharepoint.com', (error, token) => {
console.log(error, token);
});
}
I'm already logged into the SharePoint site, so with this config everything happens automatically and I see a JWT access token logged to the console. However, when I inspect the token, I see that the audience is <my-client-id>. When making a call to https://<my-tenant>.sharepoint.com/_api/v1.0/me using the access token, I then get a 401 response with the following error message:
{"error_description": "Exception of type 'Microsoft.IdentityModel.Tokens.AudienceUriValidationFailedException' was thrown."}
I'm pretty sure this all boils down to me not understanding the OAuth2 flow properly, but... how can I acquire a token that SharePoint can actually be used with SharePoint? Am I thinking about this the wrong way? It kinda defeats the purpose if the token retrieved by my app can only be used to authenticate against my own app.
Getting an access token to SharePoint is well described here:
OneDrive for Business authentication and sign in
You should consider first getting a token to the Discovery Endpoint:
Using an access token received for resource
https://api.office.com/discovery/ you can make a request to the
discovery API to learn which services are available
If the call is successful, the response body contains JSON data with
information about the services available for the user and your app.
{
"#odata.context": "https:\/\/api.office.com\/discovery\/v1.0\/me\/$metadata#allServices",
"value": [
{
"#odata.type": "#Microsoft.DiscoveryServices.ServiceInfo",
"capability": "MyFiles",
"serviceApiVersion": "v2.0",
"serviceEndpointUri": "https:\/\/contoso-my.sharepoint.com\/_api\/v2.0",
"serviceResourceId": "https:\/\/contoso-my.sharepoint.com\/"
}
]
}
There you should get your valid Resource ID... but the issue here may just be that you did not include a forwardslash (/) at the end of the Resource URL in your sample code.
I'm working on some test app, that uses auth0 and IONIC. I have established connection with auth0, and now i want to get user data by this code:
$http({
method: 'GET',
url: 'https://api.instagram.com/v1/users/self/?access_token='+store.get('accessToken')
}).then(function successCallback(response) {
console.log(response);
}, function errorCallback(response) {
console.log(response);
});
I get 400 Access-Control-Allow-Origin error. Can anybody tell me what to do? I can't find anythink on internet that'll help me...
Disclosure: I work for Auth0
The AccessToken returned at the end of Auth0 Login flow is an access token valid for calling Auth0's API's and not Instagrams. In order to do this you will need the Identity Provider's access token in this case that is Instagram.
The complete flow will look like the following
User Logs in from Instagram
Your IONIC app makes a call to your server
Your server fetches the IdP Access Tokens from Auth0 using either a non-interactive client flow or using management api v2
Your server makes the call to Instagram
You can do this via a webtask the following example highlights the flow to fetch the IdP Access Token via Management API v2 https://github.com/vikasjayaram/ext-idp-api-webtask
I am suggesting the flow because Starting Aug 16 2016 these tokens will not be sent back in profile.identities array the as they are so far.