This project demonstrates how to build an ASP.NET Core Web API that interacts with Azure AI Foundry Agents using the Fabric Data agent tool. The API implements the OAuth 2.0 On-Behalf-Of (OBO) flow to exchange user tokens for service tokens, enabling secure, delegated access to Azure AI services.
The solution consists of three main components:
- Web API (Server): ASP.NET Core API that receives user tokens and exchanges them via OBO flow to access Azure AI Foundry
- Client Application: An Entra ID application that obtains user tokens to call the Web API
- Azure AI Foundry: The AI service that hosts agents with Fabric Data agent capabilities
User → Client App → Obtain User Token → Call Web API with Bearer Token
↓
Web API exchanges token via OBO flow
↓
Azure AI Foundry validates OBO token
↓
Create Agent with Fabric Data agent tool
↓
Execute Agent and return results
- Azure subscription with access to Azure AI Foundry
- Microsoft Fabric workspace with an active capacity
- Azure AI Foundry project with a Fabric connection configured
- Permissions to create Entra ID app registrations
- .NET 9.0 SDK or later
This app registration represents your Web API service.
- Navigate to Azure Portal → Entra ID → App registrations
- Click New registration
- Set the following:
- Name:
API app(or your preferred name) - Supported account types:
Accounts in any organizational directory and personal Microsoft accounts - Redirect URI: Leave blank for now
- Name:
- Click Register
- Note the Application (client) ID and Directory (tenant) ID
-
Go to Expose an API in the left menu
-
Click Add a scope
-
Set Application ID URI to
api://<your-client-id>(e.g.,api://599719A0-8583-4A38-B7AE-3F7EAC025E87) -
Add the following scope:
Scope 1: user_impersonation
- Scope name:
user_impersonation - Who can consent:
Admins and users - Admin consent display name:
User Impersonation - Admin consent description:
User impersonation - User consent display name:
User Impersonation - User consent description:
User Impersonation - State: Enabled
- Scope name:
Add the following API permissions:
-
Click API permissions → Add a permission
Azure Machine Learning Services
- Resource App ID:
18a66f5f-dbdf-4c17-9dd7-1634712a9cbe - Permission ID:
1a7925b5-f871-417a-9b8b-303f9f29fa10(Delegated) - Type: Scope
- Resource App ID:
-
Click Grant admin consent for your tenant
- Go to Certificates & secrets
- Click New client secret
- Set Description:
api secret - Set Expires: Choose appropriate expiration (e.g., 12 months)
- Click Add
- Copy the secret value immediately (you won't be able to see it again)
- Go to Authentication
- Under Advanced settings:
- Set Allow public client flows:
Yes
- Set Allow public client flows:
- Add Redirect URI:
- Platform:
Web - URI:
https://localhost:7422(adjust to your API's URL)
- Platform:
- Under Implicit grant and hybrid flows, enable:
- Access tokens
- ID tokens
This app registration represents the client application that will call your Web API.
- Navigate to Entra ID → App registrations
- Click New registration
- Set the following:
- Name:
Client app(or your client app name) - Supported account types:
Accounts in any organizational directory and personal Microsoft accounts - Redirect URI:
Web→https://localhost/signin-oidc
- Name:
- Click Register
- Note the Application (client) ID
- Click API permissions → Add a permission → My APIs
- Select your API app
- Check the delegated permissions:
user_impersonation
- Click Add permissions
- Click Grant admin consent for your tenant
- Go to Certificates & secrets
- Click New client secret
- Set Description:
client-secret - Set Expires: Choose appropriate expiration
- Click Add
- Copy the secret value immediately
- Go to Authentication
- Ensure redirect URI is set to:
https://localhost/signin-oidc
To avoid consent prompts, pre-authorize the client app in the Web API registration:
- Go back to your API app registration
- Navigate to Expose an API
- Under Authorized client applications, click Add a client application
- Enter the Client ID of your
Client appapp - Check scopes:
user_impersonation
- Click Add application
- Navigate to Azure AI Foundry
- Create or select an existing project
- Note the Project endpoint (e.g.,
https://yourproject.services.ai.azure.com/api/projects/name-of-project)
- In your AI Foundry project, go to Settings → Connected resources
- Create a connection to your Microsoft Fabric workspace
- Ensure your Fabric capacity is running
- Note the Connection ID (full resource path):
/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.CognitiveServices/accounts/<account-name>/projects/<project-name>/connections/<connection-name>
Update appsettings.json with your configuration values:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"AzureAI": {
"Endpoint": "https://<your-project>.services.ai.azure.com/api/projects/<project-name>",
"TenantId": "<your-tenant-id>",
"ClientId": "<web-api-client-id>",
"ClientSecret": "<web-api-client-secret>",
"ConnectionId": "/subscriptions/<subscription-id>/resourceGroups/<rg>/providers/Microsoft.CognitiveServices/accounts/<account>/projects/<project>/connections/<connection>"
}
}Configuration values:
- Endpoint: Your Azure AI Foundry project endpoint
- TenantId: Your Entra ID tenant ID
- ClientId: The Application ID of your API app registration
- ClientSecret: The client secret you created for the API app app
- ConnectionId: The full resource path to your Fabric connection
Before testing, start the Web API application:
dotnet runThe API will start and listen on the configured port (typically http://localhost:5287). Keep this terminal running while you test the API.
The project includes a .http file for testing with Visual Studio or REST Client extensions.
-
Open the URL in a browser (replace with your values):
https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/authorize?client_id=<client-app-id>&response_type=code&redirect_uri=https://localhost/signin-oidc&response_mode=query&scope=api://<web-api-client-id>/user_impersonation&state=12345 -
Sign in and consent to permissions
-
Copy the
codeparameter from the redirect URL
Update the .http file with the authorization code:
POST https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded
client_id=<client-app-id>
&client_secret=<client-app-secret>
&grant_type=authorization_code
&code=<authorization-code-from-step-1>
&redirect_uri=https://localhost/signin-oidc
&scope=api://<web-api-client-id>/user_impersonationPOST http://localhost:5287/run-agent/
Accept: application/json
Authorization: Bearer <access-token-from-step-2>Follow the same flow but use your preferred HTTP client.
-
Token Extraction: The Web API extracts the bearer token from the
Authorizationheaderstring? originalToken = ExtractBearerToken(context);
-
On-Behalf-Of Token Exchange: Creates an
OnBehalfOfCredentialto exchange the user tokenvar projectClient = new AIProjectClient( endpoint, new OnBehalfOfCredential(tenantId, clientId, clientSecret, originalToken) );
-
Agent Creation: Creates a Persistent Agent with the Fabric Data agent tool
MicrosoftFabricToolDefinition fabricTool = new( new FabricDataAgentToolParameters(connId) ); PersistentAgent agent = await agentClient.Administration.CreateAgentAsync( model: "gpt-4.1", name: $"my-agent-{Guid.NewGuid()}", instructions: "You are a helpful agent.", tools: [fabricTool] );
-
Thread Creation and Execution: Creates a thread, sends a message, and runs the agent
PersistentAgentThread thread = await agentClient.Threads.CreateThreadAsync(); PersistentThreadMessage message = await agentClient.Messages.CreateMessageAsync( thread.Id, MessageRole.User, "What insights can you provide from the Fabric resource?" ); ThreadRun run = await agentClient.Runs.CreateRunAsync(thread, agent);
-
Response Processing: Polls for completion and returns the agent's response
The OBO flow allows your Web API to call downstream services (Azure AI Foundry) on behalf of the authenticated user. This maintains the security context throughout the call chain.
Benefits:
- User identity is preserved
- Fine-grained access control
- Audit trail shows actual user, not service principal
The MicrosoftFabricToolDefinition enables your agent to query and analyze data from Microsoft Fabric workspaces. The agent can:
- Access Fabric data sources
- Run queries on behalf of the user
- Provide insights based on available data