1

I am working on creating a python application which will use the Microsoft Security Graph APIs. I have followed the sample provided here with no problems. I now want to be able to create a python application which can obtain the access token (and refresh it when needed) without using a web browser.

So far I have created a new application with SecurityEvent.Read.All and SecurityEvent.ReadWrite.All permissions under both Delegated Permissions and Application Permissions. I then went to the following url in a web browser to grant my application consent and logged in with my tenant admin:

https://login.microsoftonline.com/common/adminconsent?
        client_id=APPLICATION_ID
        &state=12345
        &redirect_uri=REDIRECT_URL  

Next, I assume I want to follow the steps here to make a POST call to obtain the token. Below is an example of how I am doing that.

d = {
    "client_id": <client_id>,
    "scope": ["https://graph.microsoft.com/.default"],
    "client_secret": <client_secret>,
    "grant_type": "client_credentials"
}
r = requests.post("https://login.microsoftonline.com/common/oauth2/v2.0/token", data=d)

The following is the response I recieve

{
  "token_type": "Bearer",
  "expires_in": 3600,
  "ext_expires_in": 0,
  "access_token": "eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFDNXVuYTBFVUZnVElGOEVsYXh0V2pUR2cxQV9PR0FJWmx3T1V0b2hMNHdWN2hURHVoQTJSTzIyQnY0cGljcGJ2UmkwdEdpcmY0Q2cxaDhRZF9RamUzX2l0LUhfT1VhTnJRaDFxYXpINWtIRENBQSIsImFsZyI6IlJTMjU2IiwieDV0IjoiaTZsR2szRlp6eFJjVWIyQzNuRVE3c3lISmxZIiwia2lkIjoiaTZsR2szRlp6eFJjVWIyQzNuRVE3c3lISmxZIn0.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC83MmY5ODhiZi04NmYxLTQxYWYtOTFhYi0yZDdjZDAxMWRiNDcvIiwiaWF0IjoxNTQwNDE3MjI0LCJuYmYiOjE1NDA0MTcyMjQsImV4cCI6MTU0MDQyMTEyNCwiYWlvIjoiNDJSZ1lMRDUvK2RINkplbC9EK1RHRmZlaVNqMUJnQT0iLCJhcHBfZGlzcGxheW5hbWUiOiJTZWN1cml0eSBHcmFwaCBQT0MiLCJhcHBpZCI6IjMxMjA0MGRmLWIyZmUtNDI1Ni04ZWZkLTk1NDYyOTVjNWZhNyIsImFwcGlkYWNyIjoiMSIsImlkcCI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzcyZjk4OGJmLTg2ZjEtNDFhZi05MWFiLTJkN2NkMDExZGI0Ny8iLCJ0aWQiOiI3MmY5ODhiZi04NmYxLTQxYWYtOTFhYi0yZDdjZDAxMWRiNDciLCJ1dGkiOiJnLUtlY1dkZXcwQzV2cjBoLUhGZ0FBIiwidmVyIjoiMS4wIiwieG1zX3RjZHQiOjEyODkyNDE1NDd9.JGu6fjJk_vVvG_4NYRBfZto6nW9YRWh43JzhrlcFqFYAnJSJvWDlHbzka_H3gUKkZernQanzjI6AumER9mOtapmj1qhu_58pCuL2lTl2ubj1MTBTYOpUX3hlKgN16AeyvjO1x95LKDO9xAcIYLXEmwbkNw87x7YxZ1lKBA59c1BCCILmqMf86E7CDExf7EPqbqAPdCI6FPkStx5CJ0YnvAN2Uk5EHloTL3BTXMqMmT05h7OAvZRogkIk4aeGof1OXKcqXw7dJbzYg8XiEeXdAYhA1ld6VEwiVBMSpqf4w476Ksvr8JUbg-xhAmGoU8CrXBB4em5Gv2ko89-qP49nUA"
}

With the now obtained access token, I am trying to call the /alerts endpoint. Below is how that is being done.

headers = {
    "Content-type": "application/json",
    "Authorization": "Bearer " + <access_token>,
}
alerts = requests.get("https://graph.microsoft.com/v1.0/security/alerts", headers=headers)

Instead of getting alerts returned back this is what the response looks like to me:

{
    "error": {
    "code": "UnknownError",
    "message": "Auth token does not contain valid permissions or user does not have valid roles. Please see document at https://techcommunity.microsoft.com/t5/Using-Microsoft-Graph-Security/Authorization-and-Microsoft-Graph-Security-API/m-p/184376",
    "innerError": {
      "request-id": "1319d099-7b14-4eb0-9834-4614d5231085",
      "date": "2018-10-24T21:23:16"
    }
  }
}

Do I somehow have the permissions wrong?

Marc LaFleur
  • 31,987
  • 4
  • 37
  • 63
walshbm15
  • 113
  • 1
  • 11

2 Answers2

0

Why is this getting returned for me? Am I missing a step?

You are confusing Graph API and AAD Graph API. You should follow the following docs to implement client credentials flow:

Register your app.
Configure permissions for Microsoft Graph on your app.
Get administrator consent.
Get an access token.
Use the access token to call Microsoft Graph.

And more information on how to use Graph Security API.

Seiya Su
  • 1,836
  • 1
  • 7
  • 10
  • I have followed these steps: granted `SecurityEvents.Read.All` and SecurityEvent.ReadWrite.All` permission to my application. Given admin consent by going to `https://login.microsoftonline.com/common/adminconsentclient_id=APPLICATION_ID&state=12345&redirect_uri=REDIRECT_URL` from a web browser and logging in with an admin account. Then got an access token from the /token endpoint and used it to call the /alerts security endpoint. After changing the scope to what Marc suggested above I could get a token and call security APIs, but it returns `Auth token does not contain valid permissions` – walshbm15 Oct 24 '18 at 18:25
  • If you see the docs above, you can get the correct scope:https://graph.microsoft.com/.default. Marc have pointer this in his answer. – Seiya Su Oct 25 '18 at 05:13
0

You're extremely close. The issue here is that the scope value https://graph.microsoft.com/v1.0/security/alerts/.default is incorrect.

If you're looking to use the Security APIs, you would want to include either SecurityEvents.Read.All or SecurityEvents.ReadWrite.All in your app's registration (via https://apps.dev.microsoft.com).

Important: Whenever you change the scopes for your application, you must repeat the Admin Consent process. Admin Consent only applies to the scopes you had configured at the time Consent was granted.

Once this is complete, you need to tell the /token endpoint to use the pre-registered scopes. This is done by setting the scope property to https://graph.microsoft.com/.default. What you're doing here is telling it you want to use the Pre-registered (.default) scopes for Microsoft Graph (https://graph.microsoft.com/):

d = {
    "client_id": <client_id>,
    "scope": ["https://graph.microsoft.com/.default"],
    "client_secret": <client_secret>,
    "grant_type": "client_credentials"
}
r = requests.post("https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token", data=d)

UPDATE

There is an additional issue with the /token endpoint you're using. When using client_credentials you cannot use the /common tenant. Since there isn't a user authenticating, there is no way for AAD to discover which tenant it should authenticate against. Without knowing which tenant, it cannot determine which scopes should get applied, which in turn, results in a token without any scopes.

You need to explicitly provide the tenant ID you're looking to obtain the token for. You can either use the Tenant's ID (a GUID) or Domain:

https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token

https://login.microsoftonline.com/tenantdomain.onmicrosoft.com/oauth2/v2.0/token
Marc LaFleur
  • 31,987
  • 4
  • 37
  • 63
  • Hi @marc-lafleur, thanks for the response. When I change the scope to `["https://graph.microsoft.com/.default"]` it returns back an access token correctly. However, when I try to call an API afterward (ie: `requests.get("https://graph.microsoft.com/v1.0/security/alerts", headers=headers)`) I am presented I am presented with the following UnknownError: `"message": "Auth token does not contain valid permissions or user does not have valid roles. Please see document at https://techcommunity.microsoft.com/t5/Using-Microsoft-Graph-Security/Authorization-and-Microsoft-Graph-Security-API/m-p/184376"` – walshbm15 Oct 24 '18 at 14:04
  • This is what I was covering in the first half of my answer. You need to add `SecurityEvents.Read.All` to your app's registration and execute Admin Consent. At the moment, one or both of these steps hasn't happened so the token it generates simply doesn't include that permission (i.e. you can't use that scope until an Admin consents to your app using that scope). – Marc LaFleur Oct 24 '18 at 16:29
  • Yes, I have gone to https://apps.dev.microsoft.com and added `SecurityEvents.Read.All` and `SecurityEvents.ReadWrite.All` permissions to the application under both `Delegated Permissions` and `Application Permissions`. Then went to `https://login.microsoftonline.com/common/adminconsentclient_id=APPLICATION_ID&state=12345&redirect_uri=REDIRECT_URL` from a web browser and logged in with my tenant admin. That is my understanding of the steps to grant permissions, however, when I get an access token and call the /alerts endpoint I still get the same error message. – walshbm15 Oct 24 '18 at 17:57
  • Can you edit your question and add the token you're getting back? – Marc LaFleur Oct 24 '18 at 19:53
  • DOH! I figured out what was wrong. This is caused by trying to use Client Credentials with the Common endpoint. I've updated my answer. – Marc LaFleur Oct 25 '18 at 13:26
  • @walshbm15 I'm facing the same issue with a Javascript-based application (https://stackoverflow.com/questions/55814456/graph-security-endpoint-throwing-an-http-403-with-adaljs/55817573?noredirect=1#comment98408134_55817573). Did you ever get this working? – Ray Terrill Apr 28 '19 at 21:45
  • I did finally get it working. I had to make sure I had the correct permissions and granted consent with the correct user, can't grant consent with the overall admin (I want to say the user to give consent had to be a security admin but I might be wrong on that, sorry it has been a little while). Also I had it work with the SecurityEvents.Read.All and SecurityEvents.ReadWrite.All being app permissions not delegated permissions. – walshbm15 Apr 30 '19 at 01:06