I have a basic Identityserver4 implementation based on the quick start sample.
In my startup I have the following:
public void ConfigureServices(IServiceCollection services)
{
// configure identity server with in-memory stores, keys, clients and scopes
services.AddIdentityServer()
.AddTemporarySigningCredential()
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients());
}
public void Configure(IApplicationBuilder app)
{
...
app.UseIdentityServer();
}
I want to extend the IdentityServer4 workflow so that after the access token is generated I can run business logic (based on the claims in the access token) and modify the response send to the calling client. I tried creating a .NET core middleware but it seems the IdentityServer middleware short-circuits the rest of the pipeline (no middleware place after the UseIdentityServer will be executed).
Are they any extension method in Identityserver4 that I can use to always modify the response issued by IdentityServer4? I am using the credentials grant. Essentially I want to run some business logic to modify the response send to the client once IdentityServer4 is done with its workflow
Unfortunately, there is no way to do that.
When you request any IdentityServer endpoint, IdentityServer middleware short-circuits the rest of the pipeline.
You can check source code:
IdentityServerMiddleware class.
I believe it was done for a reason. But if you really need to modify the response, you have at least three options:
- Create a fork and remove
return
operator from
IdentityServerMiddleware
Invoke
method (be careful to short-circuit the rest of the pipeline adding return
into your last middleware).
- Create your own
IdentityServerMiddleware
, IdentityServerApplicationBuilderExtensions
implementations and use
them instead of default.
Place your middleware before the UseIdentityServer. Your middleware should look like this:
public ResponseBodyEditorMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
// get the original body
var body = context.Response.Body;
// replace the original body with a memory stream
var buffer = new MemoryStream();
context.Response.Body = buffer;
// invoke the next middleware from the pipeline
await _next.Invoke(context);
// get the body as a string
var bodyString = Encoding.UTF8.GetString(buffer.GetBuffer());
// make some changes
bodyString = $"The body has been replaced!{Environment.NewLine}Original body:{Environment.NewLine}{bodyString}";
// update the memory stream
var bytes = Encoding.UTF8.GetBytes(bodyString);
buffer.SetLength(0);
buffer.Write(bytes, 0, bytes.Length);
// replace the memory stream with updated body
buffer.Position = 0;
await buffer.CopyToAsync(body);
context.Response.Body = body;
}