Extract logged in user's email from B2C tenant

65 Views Asked by At

I am building a python flask web app hosted in Azure that stores a pic in a blob file and at the same time stores info about that picture in an Azure database for PostgreSQL flexible server.

The user signs up/ logs in via a B2C user flow, and the users information is kept in the users tab on the B2C tenant page.

In the info database, one of the fields is "user_email". The idea was that I fetch the users email from the B2C tenant and send that to the database along with all the other info that pertains to the picture in the blob db.

I have tried using the MS graph API:

msal_authority = f"https://login.microsoftonline.com/{tenant_id}"

msal_scope = ["https://graph.microsoft.com/.default"]

msal_app = ConfidentialClientApplication(
    client_id=client_id,
    client_credential=client_secret,
    authority=msal_authority,
)

result = msal_app.acquire_token_silent(
    scopes=msal_scope,
    account=None,
)

if not result:
    result = msal_app.acquire_token_for_client(scopes=msal_scope)

if "access_token" in result:
    access_token = result["access_token"]
else:
    raise Exception("No Access Token found")

headers = {
    "Authorization": f"Bearer {access_token}",
    "Content-Type": "application/json",
}

response = requests.get(
    url="https://graph.microsoft.com/v1.0/users",
    headers=headers,
)

app.logger.debug(json.dumps(response.json(), indent=4))

However, I am getting the error: "ClientAuthenticationError: the current credential is not configured to acquire tokens from tenant: 12345678910", but the tenant id '12345678910" is not the tenant id of the B2C tenant, it is the tenant id of the main directory in which the B2C tenant sits. I set the b2c tenant id as the tenant id when setting the environment variables such as the client id and client secret earlier in the code.

Is it normal that it's trying to acquire tokens from the main directory? I would have thought once the user had logged in and was "live" in the b2c tenant, there should be no need to interact with the main directory, authentication-wise. Is there a configuration needed to allow the B2C tenant to get a token from the main directory or have I misused the graph API and am interfacing with the main dir and not the B2C dir?

1

There are 1 best solutions below

4
Rukmini On

To retrieve the Azure B2C tenant users, create an application in Azure AD B2C tenant and add User.Read.All application type API permission:

enter image description here

And make use of below code to get the list of Azure AD B2C tenant users with their mail ID:

import requests
import json
from msal import ConfidentialClientApplication

client_id = "ClientIDofB2CApp"
client_secret = "ClientSecret"
tenant_id = "TenantIDOfB2C"

authority = f"https://login.microsoftonline.com/{tenant_id}"
app = ConfidentialClientApplication(
    client_id=client_id,
    client_credential=client_secret,
    authority=authority
)

scopes = ["https://graph.microsoft.com/.default"]
result = app.acquire_token_for_client(scopes=scopes)
access_token = result["access_token"]

headers = {
    "Authorization": f"Bearer {access_token}",
    "Content-Type": "application/json"
}

response = requests.get(
    url="https://graph.microsoft.com/v1.0/users",
    headers=headers
)

if response.status_code == 200:
    users = response.json()["value"]
    for user in users:
        print(user["userPrincipalName"])
else:
    raise Exception("Failed to fetch users from Microsoft Graph API")

enter image description here

Note that: If you want to retrieve the details of the logged in user, then you need to make use of delegated flow.

Grant User.Read delegated API permission to the Azure AD B2C application.

enter image description here

  • Enable the following mobile and desktop flows and configure http://localhost:60276 as redirect URL.

Make use of below code:

import msal
import requests
import json

app = msal.PublicClientApplication(
    "AzureADB2CappID", 
    authority="https://login.microsoftonline.com/AzureADB2CTenantID",
    client_credential=None
)

scopes = ["https://graph.microsoft.com/.default"]

result = app.acquire_token_interactive(scopes=scopes)

if "access_token" in result:
    access_token = result["access_token"]
else:
    error_message = result.get("error_description", "No Access Token found")
    raise Exception(error_message)

headers = {
    "Authorization": f"Bearer {access_token}",
    "Content-Type": "application/json"
}

response = requests.get(
    url="https://graph.microsoft.com/v1.0/me",
    headers=headers
)

if response.status_code == 200:
    user_details = response.json()
    print(json.dumps(user_details, indent=4))
else:
    raise Exception("Failed to fetch user details from Microsoft Graph API")

enter image description here

If still the issue persists, check the below:

  • Make sure to pass the Azure AD B2C tenant ID.
  • Make sure to pass the ClientID of Azure B2C application.
  • Make sure you are passing valid authority https://login.microsoftonline.com/AzureADB2CTenantID