Platform
Platform
Drop-In Authentication
Passkeys
Phishing-resistant, FIDO2/WebAuthn
Biometric authentication
Face and device-native biometrics
WhatsApp OTP
Global reach, lower cost than SMS
Email OTP
Universal second factor
App push authentication
Native device push notifications
Palm biometrics
Contactless identity verification
All authentication methods
KEY FEATURES
No-code rules engine
Step-up auth, risk policies, alerts
User observability
Audit trails, dynamic linking
Risk-based authentication
Adaptive MFA by context
Session management
Persistent sessions across channels
Digital credentials API
Verify sovereign digital IDs
Pre-built UI
Fastest deployment path
Passkeys
Deploy phishing-resistant passkeys across web and mobile in days
Solutions
Solutions
USE CASE
Account Takeover Prevention
Stop ATO without adding friction
Go Passwordless
Replace passwords with passkeys
Account Recovery
Secure self-service recovery flows
Call Centre Authentication
Verify callers without KBA
SMS Cost Optimisation
Cut OTP costs up to 90%
Existing Apps (Drop-In)
Add auth without re-architecting
Palm biometric payments
Contactless in-store payments
INDUSTRY
Financial Services & Banking
Secure high-value transactions
Healthcare
Authentication for ePHI access
Loyalty Programs
Protect points and member accounts
ROLE
Engineering
Fast integration, flexible SDKs
Product
No-code flows, conversion insights
Cybersecurity
Risk policies, compliance, audit trails
PricingCustomers
Resources
Resources
LEARN
Blog
Guides
Regulatory
Templates
Docs
COMPANY
About Us
Why Authsignal
Partners
Careers
Security
Contact
INTEGRATIONS
Amazon Cognito
Auth0
Azure AD B2C
Custom identity provider
Duende IdentityServer
All integrations
Docs
Start a trial
Book a callLogin
AUS Flag

Authsignal secures millions of passkey transactions out of our hosted Sydney region.

AUS Flag

Authsignal secures millions of passkey transactions out of our hosted Sydney region.

Join us today!
Right icon
Blog
/
Current article
Duende IdentityServer
Step up authentication
Adaptive MFA
Guides

Step-up authentication with Duende IdentityServer and Authsignal

Morgan French-Stagg
⬤
December 1, 2025
Share
Step-up Auth with Duende IdentityServer and Authsignal

Step-up authentication adds an extra layer of security when users try to access sensitive resources or perform high-risk actions. Instead of requiring strong authentication for every login, you can prompt users for additional verification only when they're doing something that requires it, like accessing financial data or changing account settings.

This approach strikes a balance between security and user experience. Users can browse freely with basic authentication, but when they attempt sensitive operations, they'll need to verify their identity with MFA.

In this guide, we will look into how to add step-up authentication to Duende IdentityServer using Authsignal. You will learn how to trigger additional authentication challenges based on rules you define, such as requiring MFA for specific applications or when users haven't authenticated with MFA yet in their current session.

This guide builds on our previous blog demonstrating Authsignal MFA with Duende IdentityServer: (https://www.authsignal.com/blog/articles/how-to-add-mfa-to-duende-identityserver-with-authsignal)

‍

Set up

First, follow the instructions in the Identity Server Demo Github Repository:https://github.com/authsignal/identity-server-example.

This will set up two applications:

  • IdentityServer itself
  • A demo client

‍

How it works

The StepUpInteractionResponseGenerator intercepts the authorization process at a critical point. After the user has logged in but before granting access to the requested application, it calls Authsignal's track API with context about the request.

Authsignal's rules engine evaluates this context against your configured rules. If step-up authentication is required, it returns the challenge URL. The generator then redirects the user to Authsignal's prebuilt UI to complete MFA.

Once the user completes the challenge, Authsignal redirects them back with a token. The generator validates this token before allowing the authorization code flow to continue. If validation fails, the request is denied.

‍

Implementation

Starting with the base IdentityServer example, we add a new class that decorates AuthorizeInteractionResponseGenerator with our step-up authentication logic:

using Authsignal;
using Duende.IdentityServer.Configuration;
using Duende.IdentityServer.Extensions;
using Duende.IdentityServer.ResponseHandling;
using Duende.IdentityServer.Services;
using Duende.IdentityServer.Validation;
using IdentityModel;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http.Extensions;

public class StepUpInteractionResponseGenerator(
	IdentityServerOptions options,
	ISystemClock clock,
	ILogger<AuthorizeInteractionResponseGenerator> logger,
	IConsentService consent,
	IProfileService profile,
	IAuthsignalClient authsignal,
	IHttpContextAccessor httpContextAccessor)
	: AuthorizeInteractionResponseGenerator(options, clock, logger, consent, profile)
{
	protected override async Task<InteractionResponse> ProcessLoginAsync(ValidatedAuthorizeRequest request)
	{
		var result = await base.ProcessLoginAsync(request);

		if (!result.IsLogin && !result.IsError)
		{
			// handle redirect back from authsignal
			var token = request.Raw.Get("token")?.ToString();
			if (token != null)
			{
				var validateChallengeRequest = new ValidateChallengeRequest(token);
				var validateChallengeResponse = await authsignal.ValidateChallenge(validateChallengeRequest);
				if (validateChallengeResponse.State == UserActionState.CHALLENGE_SUCCEEDED)
				{
					return result;
				}
				else
				{
					logger.LogWarning("Challenge failed: {State}", validateChallengeResponse.State);
					result.Error = OidcConstants.AuthorizeErrors.UnmetAuthenticationRequirements;
				}
			}

			var trackRequest = new TrackRequest(
				UserId: request.Subject.Identity.GetSubjectId()!,
				Action: "identity-server-authorize",
				Attributes: new TrackAttributes(
					Username: request.Subject.Claims.First(c => c.Type == JwtClaimTypes.Name)?.Value,
					RedirectUrl: httpContextAccessor.HttpContext?.Request.GetDisplayUrl(),
					IpAddress: httpContextAccessor.HttpContext?.Connection.RemoteIpAddress?.ToString(),
					UserAgent: httpContextAccessor.HttpContext?.Request.Headers["User-Agent"].ToString(),
					DeviceId: httpContextAccessor.HttpContext?.Request.Cookies["__as_aid"]?.ToString(),
					Custom: new Dictionary<string, string> {
						{ "client_id", request.Client.ClientId },
						{ "amr", string.Join(",", request.Subject.Identity.GetAuthenticationMethods()?.Select(c => c.Value)) }
					}
				)
			);

			var trackResponse = await authsignal.Track(trackRequest);

			if (trackResponse.State == UserActionState.CHALLENGE_REQUIRED)
			{
				result.RedirectUrl = trackResponse.Url;
			}
		}

		return result;
	}
}

‍

Next, inject our new IAuthorizeInteractionResponseGenerator in the ConfigureServices method in

HostingExtensions.cs :

public static WebApplication ConfigureServices(this WebApplicationBuilder builder)
{
 // [...]

	builder.Services.AddHttpContextAccessor();
	builder.Services.AddTransient<Duende.IdentityServer.ResponseHandling.IAuthorizeInteractionResponseGenerator, StepUpInteractionResponseGenerator>();
	
	return builder.Build()
}

‍

After making these changes, start IdentityServer:

cd src/IdentityServer
dotnet run

‍

Additionally, start the WebClient:

cd src/WebClient
dotnet run

‍

Navigate to https://localhost:5002 .

You will then be prompted to log in to IdentityServer (username: alice , password: alice).

If configured in the Authsignal rules engine, you may be requested to perform step-up authentication.

‍

Example step-up scenarios

Step up for specific applications

In our example we pass the client_id value from the Authorization Code Request in the track call. This allows rules to be created that only require a step-up for specific client applications.

‍

Step up if the user hasn’t completed MFA yet

In our example we pass along the amr claim from the session cookie in the track call. This allows us to define rules based on the presence of this claim, ensuring that a user isn’t required to use MFA until they attempt to access a sensitive application.

This can provide a good balance between security and usability.

‍

Wrapping up

Step-up authentication gives you fine-grained control when users need to prove their identity with MFA. By integrating Authsignal with Duende IdentityServer, you can enforce adaptive security without disrupting the user experience for low-risk activities.

You can find the complete example code in the IdentityServer demo repository. For more information about configuring rules and using Authsignal, checkout Authsignal docs, or connect with our team.

Question icon
Have a question?
Talk to an expert
NewsletterDemo PasskeysView docs
Duende IdentityServer
Step up authentication
Adaptive MFA
Guides

You might also like

The passkey UX patterns that drive adoption in 2026
Passkeys
Passkeys implementation

The passkey UX patterns that drive adoption in 2026

July 2, 2026
What is silent network authentication, and how does it work?
Silent Network Authentication
SNA

What is silent network authentication, and how does it work?

June 26, 2026
HIPAA MFA requirements and what to do before the final rule lands
Passkeys
Step up authentication
Adaptive MFA
SMS Alternative

HIPAA MFA requirements and what to do before the final rule lands

July 4, 2026

Secure your customers’ accounts today with Authsignal

Passkey demoCreate free account
Authsignal Purple Logo

Authsignal is a drop-in authentication and orchestration layer for consumer-facing businesses. Passkeys, adaptive MFA, and omnichannel verification on top of your existing identity stack. Deployed in weeks, not quarters.

AICPA SOCFido Certified
LinkedInTwitter
Platform
Drop-In Authentication
PasskeysBiometric authenticationWhatsApp OTPEmail OTPApp push authenticationPalm biometricsSMS OTPEmail OTPMagic LinksAuthenticator apps (TOTP)
View all auth methods
KEY FEATURES
No-code rules engineUser observabilityRisk-based authenticationSession managementDigital credentials APIPre-built UI
All authentication methods
Pricing
Customers
Solutions
USE CASE
Account takeovers (ATO)
Go passwordless
Call center
SMS cost optimization
Existing apps
Palm biometric payments
View all use cases
industry
Financial services
Healthcare
Marketplace
View all use cases
ROLE
Engineering
ProductCybersecurityDocs
Compare
Twilio Verify vs AuthsignalAuth0 vs AuthsignalAWS Cognito vs Authsignal + AWS Cognito
Resources
LEARN
BlogGuidesRegulatoryTemplatesDocs
COMPANY
About usWhy AuthsignalPartnersCareersSecurityContact
Integrations
Amazon Cognito
Azure AD B2C
Duende IdentityServer
Keycloak
Auth0
NextAuth.js
Custom identity provider
All integrations
United States
+1 214 974-4877
Ireland
+353 12 676529
Australia
+61 387 715 810
New Zealand
+64 275 491 983
© 2026 Authsignal - All Rights Reserved
Terms of servicePrivacy policySecuritySystem statusCookies