pythonazureazure-functionsmicrosoft-entra-id

Azure Function App using python: how to get the principal name and ID information


I have set up the identity provider for my Function App. When I access the function URL:

https://myfunc-dev-we-01.azurewebsites.net/api/http_trigger

it correctly redirects me to the Microsoft authentication page, and authentication works fine.

However, my goal is to retrieve the authenticated user's email. I attempted to extract it using the X-MS-CLIENT-PRINCIPAL header, but I’m unable to get it to work.

Here’s my current Function App code:

import azure.functions as func
import logging
import base64
import json

app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)

@app.route(route="http_trigger")
def http_trigger(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    # Retrieve the X-MS-CLIENT-PRINCIPAL header
    client_principal_header = req.headers.get('X-MS-CLIENT-PRINCIPAL')
    logging.info(f"X-MS-CLIENT-PRINCIPAL header: {client_principal_header}")
    user_name = None

    if client_principal_header:
        try:
            # Decode the Base64-encoded header
            decoded_header = base64.b64decode(client_principal_header).decode('utf-8')
            logging.info(f"Decoded X-MS-CLIENT-PRINCIPAL: {decoded_header}")
            client_principal = json.loads(decoded_header)

            # Log the entire client principal for debugging
            logging.info(f"Client Principal: {client_principal}")

            # Extract the user's name from the claims
            user_name = client_principal.get('userPrincipalName') or client_principal.get('name')
        except Exception as e:
            logging.error(f"Error decoding client principal: {e}")

    if user_name:
        return func.HttpResponse(f"Hello, {user_name}. This HTTP triggered function executed successfully.")
    else:
        return func.HttpResponse(
            "This HTTP triggered function executed successfully. However, no authenticated user information was found.",
            status_code=200
        )

Issue:

I keep getting the response:

This HTTP triggered function executed successfully. However, no authenticated user information was found.

What am I missing?

Do I need to configure additional settings in Azure AD authentication for the email claim to be included?

Is there another way to retrieve the authenticated user’s email?

This is my authentication setup

enter image description here

enter image description here

As a side note:

I'm the guest user, and identities are as ExternalAzureAD enter image description here

And people from the company itself,

enter image description here

Could this be the issue?


Solution

  • I modified your code to use the claims array from the X-MS-CLIENT-PRINCIPAL header instead of relying on top-level keys like userPrincipalName and I successfully retrieved the email ID after authenticating to the Function App.

    I have added below lines to the code.

    for claim in claims:
        if claim.get("typ") in [
            "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
            "preferred_username",
            "name"
        ]:
            user_email = claim.get("val")
    

    Complete Code:

    import azure.functions as func
    import logging
    import base64
    import json
    
    app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)
    
    @app.route(route="http_trigger")
    def http_trigger(req: func.HttpRequest) -> func.HttpResponse:
        logging.info('Python HTTP trigger function processed a request.')
        
        client_principal_header = req.headers.get('X-MS-CLIENT-PRINCIPAL')
        user_email = None
    
        if client_principal_header:
            try:
                decoded = base64.b64decode(client_principal_header).decode('utf-8')
                client_principal = json.loads(decoded)
                claims = client_principal.get("claims", [])
                for claim in claims:
                    if claim.get("typ") in [
                        "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
                        "preferred_username",
                        "name"
                    ]:
                        user_email = claim.get("val")
                        break
            except Exception as e:
                logging.error(f"Failed to parse client principal: {e}")
    
        if user_email:
            return func.HttpResponse(f"Hello, {user_email}. You are authenticated.")
        else:
            return func.HttpResponse(
                "No authenticated user information found. Please ensure authentication is configured.",
                status_code=200
            )
    

    Output:

    I successfully retrieved the email ID after authenticating to the Function App.

    enter image description here