Search code examples
c#postgresqlazureasp.net-core-webapiazure-managed-identity

Managed identity refresh token not re-setting in my postgres connection of ASP.NET Core 9 Web API


I have an ASP.NET Core 9 Web API which I need to use managed identity to connect to a postgres database.

I have this code in my Program.cs and I converted them from

var connectionString = builder.Configuration.GetConnectionString("db_conn_string")!;

builder.Services.AddEntityFrameworkNpgsql().AddDbContext<MyDbContext>(options =>
    options.UseNpgsql(connectionString)
);

to this after following this document. But there the example is for console app not for Web API:

var connectionString = builder.Configuration.GetConnectionString("db_conn_string")!;

if (builder.Configuration["ASPNETCORE_ENVIRONMENT"] != "Development")
{
    var accessToken = await new DefaultAzureCredential().GetTokenAsync(
        new TokenRequestContext(scopes: [
            "https://ossrdbms-aad.database.windows.net/.default"
        ])
    );
    connectionString = $"{builder.Configuration.GetConnectionString("db_conn_string")};Password={accessToken.Token}";
}

builder.Services.AddEntityFrameworkNpgsql().AddDbContext<MyDbContext>(options =>
    options.UseNpgsql(connectionString)
);

But this will only work once right because I'm setting the token first time and after first token expire and getting new refreshed token it is not reset in connection string even though it says that in here

Token lifetime and refreshing is handled automatically. Where possible, reuse credential instances to optimize cache effectiveness

Links i thought are useful but dont know how to continue

I'm new to these things - can someone help me with this?


Solution

  • AS PER Feb 2025

    I am using these nuget packages (csproj file):

    <ItemGroup>
      <PackageReference Include="Azure.Identity" Version="1.13.2" />
      <PackageReference Include="Npgsql" Version="9.0.2" />
      <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.3" />
    </ItemGroup>
    

    Looking at the v9.0 documentation, you can use PeriodicPasswordProvider and do something like that:

    builder.Services.AddDbContext<MyDbContext>(options =>
      options.UseNpgsql(
        builder.Configuration.GetConnectionString("db_conn_string"),
        o => o.ConfigureDataSource(dataSourceBuilder => dataSourceBuilder.UsePeriodicPasswordProvider(
          async (_, ct) =>
          {
            var tokenResponse = await new DefaultAzureCredential().GetTokenAsync(
              new TokenRequestContext(["https://<your-db-name>.database.windows.net/.default"]));
            return tokenResponse.Token;
          },
          TimeSpan.FromMinutes(55), // Interval for refreshing the token
          TimeSpan.FromSeconds(5)) // Interval for retrying after a refresh failure
        )
      )
    ); 
    

    Connectionstring sould look like that:

    Host={host};Database={database};Username={user};SSL Mode=Require;Trust Server Certificate=true
    

    As per @akseli comment, don't include the password int he connectionstring