Skip to content
Introducing the next era of Duende IdentityServer. Read our CEO’s announcement

Customizing authorize interaction redirects

When IdentityServer needs to send a user to an interaction page, like login, consent, create-account, or a custom page, it builds a redirect URL and writes an HTTP 303 response. The class responsible for this is AuthorizeInteractionPageHttpWriter, which is public and designed to be subclassed.

You might want to customize this behavior to:

  • Set a cookie before the redirect (for example, to carry state that survives the round-trip through the interaction page).
  • Append a custom query parameter to the interaction page URL (for example, a tenant identifier or a UI hint).
  • Change the redirect status code or add extra response headers.

AuthorizeInteractionPageHttpWriter implements IHttpResponseWriter<AuthorizeInteractionPageResult> and exposes three virtual methods you can override independently:

MethodResponsibility
BuildReturnUrlAsyncBuilds the URL that points back to the authorize callback endpoint.
BuildRedirectUrlAsyncCombines the interaction page URL with the return URL.
WriteResponseAsyncWrites the HTTP response (status code, Location header).

The default WriteHttpResponse implementation calls all three in sequence. You only need to override the method that covers the behavior you want to change.

Example: appending a custom query parameter

Section titled “Example: appending a custom query parameter”

The example below adds a ui_hint query parameter to every redirect URL so the interaction page can adjust its appearance based on the originating client.

CustomRedirectWriter.cs
using Duende.IdentityServer.Configuration;
using Duende.IdentityServer.Endpoints.Results;
using Duende.IdentityServer.Hosting;
using Duende.IdentityServer.Services;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
public class CustomRedirectWriter : AuthorizeInteractionPageHttpWriter
{
public CustomRedirectWriter(
IdentityServerOptions options,
IServerUrls urls,
IUiLocalesService localesService,
IAuthorizationParametersMessageStore? authorizationParametersMessageStore = null)
: base(options, urls, localesService, authorizationParametersMessageStore)
{
}
protected override async Task<string> BuildRedirectUrlAsync(
AuthorizeInteractionPageResult result,
string returnUrl,
HttpContext context)
{
var redirectUrl = await base.BuildRedirectUrlAsync(result, returnUrl, context);
// Append a ui_hint parameter so the interaction page knows which client triggered the flow.
var clientId = result.Request?.ClientId;
if (!string.IsNullOrEmpty(clientId))
{
redirectUrl += (redirectUrl.Contains('?') ? "&" : "?")
+ "ui_hint=" + Uri.EscapeDataString(clientId);
}
return redirectUrl;
}
}
Section titled “Example: setting a cookie before the redirect”

Override WriteResponseAsync when you need to write response headers or cookies in addition to the redirect itself.

CookieRedirectWriter.cs
protected override Task WriteResponseAsync(HttpContext context, string redirectUrl)
{
// Set a short-lived cookie that the interaction page can read.
context.Response.Cookies.Append("idsrv.hint", "active", new CookieOptions
{
HttpOnly = true,
Secure = true,
SameSite = SameSiteMode.Lax,
MaxAge = TimeSpan.FromMinutes(5)
});
return base.WriteResponseAsync(context, redirectUrl);
}

Register your subclass using AddHttpWriter<TResult, TWriter>() in your IdentityServer setup:

Program.cs
builder.Services.AddIdentityServer()
.AddHttpWriter<AuthorizeInteractionPageResult, CustomRedirectWriter>();

This replaces the default AuthorizeInteractionPageHttpWriter for AuthorizeInteractionPageResult responses. All other result types keep their default writers.