
Authentication and Authorization of Dapr Requests for .NET Web API
Authentication and Authorization of Dapr Requests for .NET Web API
The Problem
When a .NET Web API is deployed to Azure Container Apps as a container app, how can we authenticate and authorize requests coming from Dapr? Additionally, how can the application be setup with minimal impact to local development and testing?
Background
TL;DR: Configuring .NET Web API Auth
Dapr can be configured to pass a token (APP_API_TOKEN
) in every request header to the attached application.
Read more on Dapr token
configuration in the Dapr docs.
Azure Container Apps using Dapr will automatically assign the APP_API_TOKEN
when a new revision of a container app is created.
The token is provided to both the container app and the container app’s Dapr sidecar. Read more
on Microsoft’s
Container Apps docs.
The Dapr .NET SDK does provide a way to authenticate and authorize requests using the Dapr API token. The SDK docs can be found here but do not outline exactly how to do set this up. The code for the SDK can be found on github, which helped me figure out which methods to call.
Configuring .NET Web API Auth
Before we get started, this article assumes that you can create a .NET Web API project with Dapr running as a sidecar, configured in docker-compose. Check out my article Dapr Sidecar with docker-compose to see an example of an application with this configuration.
Check out the repo which contains all of the code referenced in this post! In this example, there is an APISampleBFF
, which publishes messages using the Dapr SDK. There is a second
API SampleProcessingService
, which subscribes to messages using the Dapr SDK. The
SampleProcessingService
will be configured to authenticate and authorize requests from Dapr.
1. Initial Solution Configuration
Create a solution with a .NET Web API project. Configure the application to run with docker-compose.
This docker-compose example file sets up each API with the associated Dapr sidecar, as well as a Redis container which will be used as a message broker for the Dapr pubsub component.
2. Add and Configure Dapr SDK in .NET Web API
Install the Dapr.AspNetCore
package from nuget.
In Program.cs
, add the following lines:
builder.Services.AddControllers().AddDapr(); // Adds a DaprClient singleton for use in the app
// ... More setup code
var app = builder.Build();
app.UseRouting();
app.UseCloudEvents();
app.MapSubscribeHandler();
Add pubsub.yml to the DaprComponents folder.
3. Publish Messages with Dapr SDK
In SampleBff.InitiateBackgroundProcessingController
, here’s a sample endpoint which publishes 10 messages.
private readonly DaprClient _client;
// The client is injected with the AddDapr() due to method call in Program.cs
public InitiateBackgroundProcessingController(DaprClient client)
{
_client = client;
}
[HttpPost]
public async Task<IActionResult> Post()
{
for (int i = 0; i < 10; i++)
{
var message = new MessageFromBff($"Message from BFF number {i}", DateTime.UtcNow);
await _client.PublishEventAsync("pubsub", "message-from-bff", message);
}
return Accepted();
}
4. Subscribe to Messages with Dapr SDK
In SampleProcessingService.MessageFromBffController
, here’s a sample endpoint which subscribes
to the message-from-bff
topic.
[HttpPost]
[Topic("pubsub", "message-from-bff")]
public IActionResult Post(MessageFromBff message)
{
Console.WriteLine(message.Description);
return Accepted();
}
At this point, there is no authentication or authorization setup in the applications. Any
user or system can post directly to the MessageFromBffController
.
5. Add Dapr Authentication to .NET Web API
For the next steps, I will only be adding authentication and authorization to the
SampleProcessingService
API. This way, we can still post to SampleBff
to publish messages.
In Program.cs
, add the following line:
builder.Services.AddAuthentication().AddDapr(); // Adds Dapr authentication
Note: This works for .NET 7. If you’re using .NET 6, you must provide an authentication scheme, so the line will become:
builder.Services.AddAuthentication("Dapr").AddDapr(); // Adds Dapr authentication
6. Add Dapr Authorization in .Net Web API
In Program.cs
, add the following lines:
// After AddAuthentication
builder.Services.AddAuthorization(options =>
{
options.AddDapr(); // Adds Dapr authorization
});
// ... More setup code
app.UseAuthorization();
app.UseAuthorization();
// ... More app configurations
app.MapControllers().RequireAuthorization(); // Forces all controllers to require authorization
At this point, run the application, publish messages, and take a look at the Dapr logs. You will most likely see messages that look like this:
time="2023-05-26T02:36:02.08077217Z" level=error msg="Error processing Redis message
1685068562062-0: retriable error returned from app while processing pub/sub event
658ee441-3262-4ca8-89d9-e8d442598a77, topic: message-from-bff, body: . status code
returned: 401" app_id=sampleprocessingservice instance=6e20431c34dc scope=dapr.contrib
7. Update docker-compose with Environment Variables
The final piece of the puzzle is to add the APP_API_TOKEN
environment variable in the docker-compose
file for the API and its associated Dapr sidecar. For example:
sampleprocessingservice:
image: ${DOCKER_REGISTRY-}sampleprocessingservice
build:
context: .
dockerfile: SampleProcessingService/Dockerfile
environment:
- APP_API_TOKEN=109be48e-8eab-41a9-92a8-496656c9602f
depends_on:
- daprauthredis
sampleprocessingservice-dapr:
image: "daprio/daprd:latest"
command: [ #... commands
]
volumes:
- "./DaprComponents/:/DaprComponents"
environment:
- APP_API_TOKEN=109be48e-8eab-41a9-92a8-496656c9602f
As far as I can tell, the token can be any string as long as they match. I just use randomly
generated GUIDs for local development, but I even tried setting the token to HERESATOKENFORYA
and authorization still works.
Why This Works with Azure Container Apps
Again, per Microsoft’s documentation, Azure Container Apps will automatically assign the API and the Dapr sidecar the same app API token. Now that the API is configured with Dapr authentication and authorization, endpoints are secured yet allow traffic from Dapr.
Wrapping It Up
Now that the API is setup with authentication and authorization for Dapr requests, the docker-compose configuration allows for local development without unauthorized requests. This setup mirrors the behavior that will exist in Azure Container Apps.
The API can be configured to work with multiple authentication schemes (not just Dapr’s). In the example code,
the API is setup to require authorization for all controllers. If you have multiple authentication schemes
and want to secure a specific controller for just Dapr, you can do so by decorating the controller
with [Authorize(AuthenticationSchemes = "Dapr")]
.
I hope this helps! Drop me a line if you have any questions.