1
votes

I'm writing a daemon app for my customers (multiple tenants) who are using outlook.

I'm using 2 application permissions that need admin consent - Mail.ReadBasic.All and User.Read.All. my app first needs to read all the users' ids, then get all the metadata of their emails.

I've created a new tenant with office365 to test this, let's call it - test, and sent a couple of emails between 2 users.
So, at first, I'm redirecting the admin of the test org to the adminconsent endpoint, where he/she is granting application permissions to my app. This is the URL I'm using:

https://login.microsoftonline.com/organizations/v2.0/adminconsent?
client_id=<the app ID>
&state=<some state>
&redirect_uri=<my redirect URL as written in the app configuration>
&scope=https://graph.microsoft.com/.default

After calling this endpoint I can see my app listed in the test org under the Enterprise applications and can see the relevant permissions were granted by an admin.

Since I'm not getting a code from this flow (needed for the oAuth2 authentication flow), I then need to ask the admin to login again. I'm using this URL for that:

https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize?
client_id=<same app ID>
&response_type=code
&redirect_uri=<same redirect URL>
&scope=https://graph.microsoft.com/.default+offline_access+openid+profile
&state=<some state>

After the login is successful I'm getting a code back to my redirect URL and after another request, I'm getting an access token. Using this access token I'm trying to access any of the following APIs:

But I'm getting ErrorAccessDenied with a message: Access is denied. Check credentials and try again.

Further information: I'm using python and the MSAL package to build the app (using the class - ConfidentialClientApplication) and the URLs for the authentication flow (but not for the adminconsent endpoint, as I couldn't find out how to do it)

Do you know what I'm doing wrong? I'm losing my mind over this... :(

1

1 Answers

2
votes

This page should describe everything you need: https://docs.microsoft.com/graph/auth-v2-service

The admin consent URL should be specific to the customer's tenant. You can use the word common if you want to allow signing into any tenant.

https://login.microsoftonline.com/{tenant}/adminconsent

You also must URL encode the redirect_uri param (and all other params). For some reason the example in that document is not URL encoded, but the value here must be URL encoded. You should see no colons, slashes, ampersands, etc. for this parameter.

For a different example that requests specific scopes for admin consent (instead of the default which is all the scopes you listed during your AAD client app registration) see https://docs.microsoft.com/azure/active-directory/develop/v2-admin-consent.

  1. You will receive a callback to the redirect URI to indicate everything worked. This includes the tenant ID that granted you admin consent.

  2. After that you initiate a separate token request call for the tenant ID, your application client ID and a specific requested scope. This will then return an appropriately scoped access token which you can use directly in all API calls. You can do this like so: https://docs.microsoft.com/azure/active-directory/develop/scenario-daemon-acquire-token?tabs=python#acquiretokenforclient-api

# The pattern to acquire a token looks like this.
result = None

# First, the code looks up a token from the cache.
# Because we're looking for a token for the current app, not for a user,
# use None for the account parameter.
result = app.acquire_token_silent(config["scope"], account=None)

if not result:
    logging.info("No suitable token exists in cache. Let's get a new one from AAD.")
    result = app.acquire_token_for_client(scopes=config["scope"])

if "access_token" in result:
    # Call a protected API with the access token below.
    print(result["token_type"])
else:
    print(result.get("error"))
    print(result.get("error_description"))
    print(result.get("correlation_id"))  # You might need this when reporting a bug.

Hope that helps. The article above has all the details.