Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
00ec590
Update package index with latest published versions (#44558)
azure-sdk Jan 28, 2025
3fdb4bb
Enhanced F# Literals Documentation with Comprehensive Examples and Ad…
shethaadit Jan 28, 2025
76212ab
Update live-protection.yml (#44557)
gewarren Jan 28, 2025
dfa0dfb
Fixed bug 36231. (#44556)
shethaadit Jan 28, 2025
86328be
Update package index with latest published versions (#44577)
azure-sdk Jan 28, 2025
68dd7b6
Add MSTESTEXP doc (#44575)
Evangelink Jan 28, 2025
25e9a75
code fence `into` when used as a keyword (#44563)
BillWagner Jan 28, 2025
7472d5c
Fast follow to #44513 (#44565)
BillWagner Jan 28, 2025
b41b244
Bump Microsoft.Extensions.VectorData.Abstractions (#44587)
dependabot[bot] Jan 29, 2025
da8205b
Bump the dotnet group (#44586)
dependabot[bot] Jan 29, 2025
f771737
Bump MSTest (#44588)
dependabot[bot] Jan 29, 2025
a03d788
Bump Microsoft.SemanticKernel (#44589)
dependabot[bot] Jan 29, 2025
911d387
Bump the dotnet group (#44590)
dependabot[bot] Jan 29, 2025
1a78f08
Bump the dotnet group (#44592)
dependabot[bot] Jan 29, 2025
6996da4
Bump the dotnet group (#44593)
dependabot[bot] Jan 29, 2025
3c3a3da
Bump Microsoft.SemanticKernel (#44594)
dependabot[bot] Jan 29, 2025
a1e7372
Bump the dotnet group (#44595)
dependabot[bot] Jan 29, 2025
64b58ad
Bump System.Linq.Dynamic.Core (#44596)
dependabot[bot] Jan 29, 2025
f474825
Bump the dotnet group (#44597)
dependabot[bot] Jan 29, 2025
5367d2a
Bump OpenTelemetry.Exporter.Console (#44598)
dependabot[bot] Jan 29, 2025
3c892c6
Bump MSTest.TestFramework (#44600)
dependabot[bot] Jan 29, 2025
4dcb6f3
Bump OpenTelemetry.Exporter.Console (#44599)
dependabot[bot] Jan 29, 2025
3c20b73
Bump the dotnet group (#44601)
dependabot[bot] Jan 29, 2025
013600f
Bump the dotnet group (#44602)
dependabot[bot] Jan 29, 2025
1733c63
Bump the dotnet group (#44603)
dependabot[bot] Jan 29, 2025
7874629
Bump github/codeql-action from 3.28.2 to 3.28.6 (#44604)
dependabot[bot] Jan 29, 2025
2910dcb
Bump Microsoft.Extensions.VectorData.Abstractions (#44605)
dependabot[bot] Jan 29, 2025
762089c
Bump MSTest (#44606)
dependabot[bot] Jan 29, 2025
f126215
Bump MSTest.TestFramework (#44607)
dependabot[bot] Jan 29, 2025
55a932f
Bump OpenTelemetry.Exporter.Console (#44608)
dependabot[bot] Jan 29, 2025
e5cfd53
Use 'unsafe' explicitly to have it in snippets (#44573)
BartoszKlonowski Jan 29, 2025
444d1df
Update package index with latest published versions (#44579)
azure-sdk Jan 29, 2025
a5f225f
Update MSTEST0026 doc to reflect enabled by default change in 3.8 (#4…
Youssef1313 Jan 29, 2025
1ab103f
Fixed bug 34928. (#44584)
shethaadit Jan 29, 2025
e6f894d
[Chore] Fix build suggestions 1/28 (#44582)
gewarren Jan 29, 2025
a1b948b
Distributed tracing in networking (#44063)
antonfirsov Jan 29, 2025
a78c8bc
Update ms.custom value to the new value and add addl. highlights (#44…
anandmeg Jan 29, 2025
e10e4eb
Improve credential reuse code samples (#44581)
scottaddie Jan 29, 2025
ed74092
Clarify what missing members article is about (#44400)
gewarren Jan 29, 2025
ba1042f
HttpClientFactory Keyed DI docs (#44533)
CarnaViire Jan 29, 2025
fba513c
Update guidance for Azure hosted apps connecting to Azure OpenAI (#44…
alexwolfmsft Jan 29, 2025
82b57b4
new assistants quickstart (#44536)
alexwolfmsft Jan 29, 2025
7b25772
delete irrelevant breaking change (#44443)
gewarren Jan 30, 2025
32aeb14
Be explicit about recommended actions (#44411)
gewarren Jan 30, 2025
ba08e66
Show example of multiple ContainerRuntimeIdentifiers (#44578)
MattKotsenas Jan 30, 2025
4901df4
Replace 'comprised' with 'composed' in CA2253 (#44612)
BartoszKlonowski Jan 30, 2025
2126074
Add Example for Mutually Recursive Discriminated Unions in F# (#44610)
shethaadit Jan 30, 2025
160b115
Update package index with latest published versions (#44609)
azure-sdk Jan 30, 2025
c44b3bf
Add model selection note (#44622)
alexwolfmsft Jan 30, 2025
b200601
WebSocket Keep-Alive (#44611)
CarnaViire Jan 31, 2025
1d4e0e6
Give more context about dotnet test with mtp (#44618)
Evangelink Jan 31, 2025
e78ef00
Add first level info for migration off of VSTest (#44620)
Evangelink Jan 31, 2025
f54eec3
Clarify ReferenceEquals Behavior for Value Types in Docs (#44624)
shethaadit Jan 31, 2025
a1f1c09
Update package index with latest published versions (#44630)
azure-sdk Jan 31, 2025
b0547e1
Update package index with latest published versions (#44637)
azure-sdk Jan 31, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/live-protection.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ permissions:

jobs:
live_protection_job:
name: Create comment
name: Check base branch
runs-on: ubuntu-latest

steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/scorecards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,6 @@ jobs:

# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@d68b2d4edb4189fd2a5366ac14e72027bd4b37dd # v3.28.2
uses: github/codeql-action/upload-sarif@17a820bf2e43b47be2c72b39cc905417bc1ab6d0 # v3.28.6
with:
sarif_file: results.sarif
4 changes: 4 additions & 0 deletions .openpublishing.redirection.azure.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@
{
"source_path_from_root": "/docs/azure/sdk/azure-sdk-configure-proxy.md",
"redirect_url": "/dotnet/azure/sdk/configure-proxy"
},
{
"source_path_from_root": "/docs/azure/sdk/authentication/authentication-best-practices.md",
"redirect_url": "/dotnet/azure/sdk/authentication/best-practices"
}
]
}
4 changes: 4 additions & 0 deletions .openpublishing.redirection.core.json
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,10 @@
"redirect_url": "/dotnet/core/compatibility/sdk/5.0/sdk-and-target-framework-change",
"redirect_document_id": true
},
{
"source_path_from_root": "/docs/core/compatibility/windows-forms/8.0/anchor-layout.md",
"redirect_url": "/dotnet/core/compatibility/8.0"
},
{
"source_path_from_root": "/docs/core/deploying/applications.md",
"redirect_url": "/dotnet/core/deploying/index"
Expand Down
1 change: 0 additions & 1 deletion docfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,6 @@
"docs/standard/collections/**/**.md": "dapine",
"docs/standard/commandline/**/**.md": "tdykstra",
"docs/standard/data/**/**.md": "gewarren",
"docs/standard/data/sqlite/**/**.md": "avickers",
"docs/standard/datetime/**/**.md": "adegeo",
"docs/standard/design-guidelines/**/**.md": "kcwalina",
"docs/standard/events/**/**.md": "dapine",
Expand Down
80 changes: 57 additions & 23 deletions docs/ai/how-to/app-service-aoai-auth.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,30 @@
---
title: "Authenticate and Authorize App Service to Azure OpenAI using Microsoft Entra and the Semantic Kernel SDK"
description: "Learn how to authenticate and authorize your app service application to an Azure OpenAI resource by using Microsoft Entra managed identities and the Semantic Kernel SDK for .NET."
title: "Authenticate an Azure hosted .NET app to Azure OpenAI using Microsoft Entra ID"
description: "Learn how to authenticate your Azure hosted .NET app to an Azure OpenAI resource using Microsoft Entra ID."
author: haywoodsloan
ms.topic: how-to
ms.custom: devx-track-azurecli
ms.date: 11/24/2024
ms.date: 01/29/2025
zone_pivot_groups: azure-interface
#customer intent: As a .NET developer, I want authenticate and authorize my App Service to Azure OpenAI by using Microsoft Entra so that I can securely use AI in my .NET application.
---

# Authenticate an AI app hosted on Azure App Service to Azure OpenAI using Microsoft Entra ID
# Authenticate to Azure OpenAI from an Azure hosted app using Microsoft Entra ID

This article demonstrates how to use [Microsoft Entra ID managed identities](/azure/app-service/overview-managed-identity) to authenticate and authorize an App Service application to an Azure OpenAI resource.
This article demonstrates how to use [Microsoft Entra ID managed identities](/azure/app-service/overview-managed-identity) and the [Microsoft.Extensions.AI library](/dotnet/ai/ai-extensions) to authenticate an Azure hosted app to an Azure OpenAI resource.

This article also demonstrates how to use the [Semantic Kernel SDK](/semantic-kernel/overview) to easily implement Microsoft Entra authentication in your .NET application.

By using a managed identity from Microsoft Entra, your App Service application can easily access protected Azure OpenAI resources without having to manually provision or rotate any secrets.
A managed identity from Microsoft Entra ID allows your app to easily access other Microsoft Entra protected resources such as Azure OpenAI. The identity is managed by the Azure platform and doesn't require you to provision, manage, or rotate any secrets.

## Prerequisites

* An Azure account that has an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F).
* [.NET SDK](https://dotnet.microsoft.com/download/visual-studio-sdks)
* [`Microsoft.SemanticKernel` NuGet package](https://www.nuget.org/packages/Microsoft.SemanticKernel)
* [`Azure.Identity` NuGet package](https://www.nuget.org/packages/Azure.Identity)
* [Create and deploy an Azure OpenAI Service resource](/azure/ai-services/openai/how-to/create-resource)
* [Create and deploy a .NET application to App Service](/azure/app-service/quickstart-dotnetcore)

## Add a managed identity to App Service

Your application can be granted two types of identities:
Managed identities provide an automatically managed identity in Microsoft Entra ID for applications to use when connecting to resources that support Microsoft Entra authentication. Applications can use managed identities to obtain Microsoft Entra tokens without having to manage any credentials. Your application can be assigned two types of identities:

* A **system-assigned identity** is tied to your application and is deleted if your app is deleted. An app can have only one system-assigned identity.
* A **user-assigned identity** is a standalone Azure resource that can be assigned to your app. An app can have multiple user-assigned identities.
Expand All @@ -41,6 +37,11 @@ Your application can be granted two types of identities:
1. Select **Identity**.
1. On the **System assigned** tab, toggle *Status* to **On**, and then select **Save**.

:::image type="content" source="../media/azure-hosted-apps/system-assigned-managed-identity-in-azure-portal.png" alt-text="A screenshot showing how to add a system assigned managed identity to an app.":::

> [!NOTE]
> The preceding screenshot demonstrates this process on an Azure App Service, but the steps are similar on other hosts such as Azure Container Apps.

## [User-assigned](#tab/user-assigned)

To add a user-assigned identity to your app, create the identity, and then add its resource identifier to your app config.
Expand All @@ -54,6 +55,11 @@ To add a user-assigned identity to your app, create the identity, and then add i
> [!IMPORTANT]
> After you select **Add**, the app restarts.

:::image type="content" source="../media/azure-hosted-apps/user-assigned-managed-identity-in-azure-portal.png" alt-text="A screenshot showing how to add a system assigned managed identity to an app.":::

> [!NOTE]
> The preceding screenshot demonstrates this process on an Azure App Service, but the steps are similar on other hosts such as Azure Container Apps.

---

:::zone-end
Expand Down Expand Up @@ -86,13 +92,16 @@ az webapp identity assign --name <appName> --resource-group <groupName>

:::zone-end

## Add an Azure OpenAI user role to your managed identity
## Add an Azure OpenAI user role to the identity

:::zone target="docs" pivot="azure-portal"

1. In the [Azure Portal](https://aka.ms/azureportal), navigate to the scope that you want to grant **Azure OpenAI** access to. The scope can be a **Management group**, **Subscription**, **Resource group**, or a specific **Azure OpenAI** resource.
1. In the left navigation pane, select **Access control (IAM)**.
1. Select **Add**, then select **Add role assignment**.

:::image type="content" source="../media/azure-hosted-apps/add-entra-role.png" alt-text="A screenshot showing how to add an RBAC role.":::

1. On the **Role** tab, select the **Cognitive Services OpenAI User** role.
1. On the **Members** tab, select the managed identity.
1. On the **Review + assign** tab, select **Review + assign** to assign the role.
Expand All @@ -101,53 +110,78 @@ az webapp identity assign --name <appName> --resource-group <groupName>

:::zone target="docs" pivot="azure-cli"

**Resource scope**
You can use the Azure CLI to assign the Cognitive Services OpenAI User role to your managed identity at varying scopes.

# [Resource](#tab/resource)

```azurecli
az role assignment create --assignee "<managedIdentityObjectID>" \
--role "Cognitive Services OpenAI User" \
--scope "/subscriptions/<subscriptionId>/resourcegroups/<resourceGroupName>/providers/<providerName>/<resourceType>/<resourceSubType>/<resourceName>"
```

**Resource group scope**
# [Resource group](#tab/resource-group)

```azurecli
az role assignment create --assignee "<managedIdentityObjectID>" \
--role "Cognitive Services OpenAI User" \
--scope "/subscriptions/<subscriptionId>/resourcegroups/<resourceGroupName>"
```

**Subscription scope**
# [Subscription](#tab/subscription)

```azurecli
az role assignment create --assignee "<managedIdentityObjectID>" \
--role "Cognitive Services OpenAI User" \
--scope "/subscriptions/<subscriptionId>"
```

**Management group scope**
# [Management group](#tab/management-group)

```azurecli
az role assignment create --assignee "<managedIdentityObjectID>" \
--role "Cognitive Services OpenAI User" \
--scope "/providers/Microsoft.Management/managementGroups/<managementGroupName>"
```

---

:::zone-end

## Implement token-based authentication using Semantic Kernel SDK
## Implement identity authentication in your app code

1. Add the following NuGet packages to your app:

```dotnetcli
dotnet add package Azure.Identity
dotnet add package Azure.AI.OpenAI
dotnet add package Microsoft.Extensions.Azure
dotnet add package Microsoft.Extensions.AI
dotnet add package Microsoft.Extensions.AI.OpenAI
```

The preceding packages each handle the following concerns for this scenario:

- **[Azure.Identity](https://www.nuget.org/packages/Azure.Identity)**: Provides core functionality to work with Microsoft Entra ID
- **[Azure.AI.OpenAI](https://www.nuget.org/packages/Azure.AI.OpenAI)**: Enables your app to interface with the Azure OpenAI service
- **[Microsoft.Extensions.Azure](https://www.nuget.org/packages/Microsoft.Extensions.Azure)**: Provides helper extensions to register services for dependency injection
- **[Microsoft.Extensions.AI](https://www.nuget.org/packages/Microsoft.Extensions.AI)**: Provides AI abstractions for common AI tasks
- **[Microsoft.Extensions.AI.OpenAI](https://www.nuget.org/packages/Microsoft.Extensions.AI.OpenAI)**: Enables you to use OpenAI service types as AI abstractions provided by **Microsoft.Extensions.AI**

1. In the `Program.cs` file of your app, create a `DefaultAzureCredential` object to discover and configure available credentials:

1. Initialize a `DefaultAzureCredential` object to assume your app's managed identity:
:::code language="csharp" source="./snippets/hosted-app-auth/program.cs" range="13-22":::

:::code language="csharp" source="./snippets/semantic-kernel/IdentityExamples.cs" id="tokenCredential":::
1. Create an AI service and register it with the service collection:

1. Build a `Kernel` object that includes the Azure OpenAI Chat Completion Service, and use the previously created credentials:
:::code language="csharp" source="./snippets/hosted-app-auth/program.cs" range="24-30":::

:::code language="csharp" source="./snippets/semantic-kernel/IdentityExamples.cs" id="kernelBuild":::
1. Inject the registered service for use in your endpoints:

1. Use the `Kernel` object to invoke prompt completion through Azure OpenAI:
:::code language="csharp" source="./snippets/hosted-app-auth/program.cs" range="41-46":::

:::code language="csharp" source="./snippets/semantic-kernel/IdentityExamples.cs" id="invokePrompt":::
> [!TIP]
> Learn more about ASP.NET Core dependency injection and how to register other AI services types in the Azure SDK for .NET [dependency injection](/dotnet/azure/sdk/dependency-injection) documentation.

## Related content

Expand Down
47 changes: 47 additions & 0 deletions docs/ai/how-to/snippets/hosted-app-auth/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Azure;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();

// DefaultAzureCredential attempts several auth flows in order until one is available
// For example, will discover Visual Studio or Azure CLI credentials
// in local environments and managed identity credentials in production deployments
var credential = new DefaultAzureCredential(
new DefaultAzureCredentialOptions
{
// If necessary, specify the tenant ID,
// user-assigned identity client or resource ID, or other options
}
);

// Retrieve the Azure OpenAI endpoint and deployment name
string endpoint = builder.Configuration["AZURE_OPENAI_ENDPOINT"];
string deployment = builder.Configuration["AZURE_OPENAI_GPT_NAME"];

builder.Services.AddChatClient(
new AzureOpenAIClient(new Uri(endpoint), credential)
.AsChatClient(deployment));

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}

app.UseHttpsRedirection();

app.MapGet("/test-prompt", async (IChatClient chatClient) =>
{
return await chatClient.CompleteAsync("Test prompt", new ChatOptions());
})
.WithName("Test prompt");

app.Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "http://localhost:5140",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "https://localhost:7137;http://localhost:5140",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AZURE_OPENAI_ENDPOINT": "your-azure-openai-endpoint",
"AZURE_OPENAI_GPT_NAME": "your-azure-openai-deployment-name"
}
19 changes: 19 additions & 0 deletions docs/ai/how-to/snippets/hosted-app-auth/hosted-app-auth.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>hosted_app_auth</RootNamespace>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Azure.AI.OpenAI" Version="2.1.0" />
<PackageReference Include="Azure.Identity" Version="1.13.2" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.1" />
<PackageReference Include="Microsoft.Extensions.AI" Version="9.1.0-preview.1.25064.3" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="9.1.0-preview.1.25064.3" />
<PackageReference Include="Microsoft.Extensions.Azure" Version="1.9.0" />
</ItemGroup>

</Project>
6 changes: 6 additions & 0 deletions docs/ai/how-to/snippets/hosted-app-auth/hosted-app-auth.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@hosted_app_auth_HostAddress = http://localhost:5140

GET {{hosted_app_auth_HostAddress}}/weatherforecast/
Accept: application/json

###
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.1" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.33.0" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.35.0" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.AzureAISearch" Version="1.9.0-alpha" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Redis" Version="1.9.0-alpha" />
<PackageReference Include="Microsoft.SemanticKernel.Plugins.Memory" Version="1.9.0-alpha" />
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions docs/ai/quickstarts/quickstart-ai-chat-with-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ Complete the following steps to create a .NET console app that can accomplish th
dotnet user-secrets set ModelName <your-openai-model-name>
```

> [!NOTE]
> For the `ModelName` value, you need to specify an OpenAI text embedding model such as `text-embedding-3-small` or `text-embedding-3-large` to generate embeddings for vector search in the sections that follow.

:::zone-end

## Add the app code
Expand Down
Loading
Loading