• Products
    • IdentityServer
    • IdentityServer for Redistribution
    • Backend for Frontend (BFF) Security Framework
  • Documentation
  • Training
  • Resources
    • Company Blog
    • Featured Articles
    • About
      • Company
      • Partners
      • Careers
      • Contact
    Duende Software Blog
    • Products
      • IdentityServer
      • IdentityServer for Redistribution
      • Backend for Frontend (BFF) Security Framework
      • Open Source
    • Documentation
    • Training
    • Resources
      • Company Blog

        Stay up-to-date with the latest developments in identity and access management.

      • Featured Articles
      • About
        • Company
        • Partners
        • Careers
        • Contact
      • Start for free
        Contact sales

      The role of AuthenticationProperties in ASP.NET Core

      Maarten Balliauw Head of Customer Success at Duende Software Maarten Balliauw

      published on May 27, 2025

      When working with user authentication in ASP.NET Core, you may encounter situations where you need to pass additional information through the authentication process. For example, you might want to track specific user actions, ensure they are redirected to a particular page after logging in, or pass custom parameters to an identity provider.

      The AuthenticationProperties class provides an elegant solution for these scenarios. It allows you to carry state through call sites within a specific request, maintain state throughout the authentication process, or pass additional parameters to the identity provider you are using.

      In this post, we’ll see how to use the AuthenticationProperties class effectively in your ASP.NET Core applications and explore some OpenID Connect-specific options you can use in your apps.

      What is AuthenticationProperties?

      The AuthenticationProperties class in ASP.NET Core is a simple yet powerful way to pass additional state or metadata during the authentication process.

      While it has several properties like AllowRefresh, ExpiresUtc, IssuedUtc, IsPersistent, and RedirectUri that reflect various characteristics of an authentication session, these values are backed by two dictionaries:

      • Items - Contains state values about the authentication session and is carried throughout the authentication process.
      • Parameters - Contains parameters passed to the authentication handler and used for flowing data between call sites in the same request.

      Let’s look at some examples of where and how they can be used!

      Using AuthenticationProperties.Items in your application

      The Items dictionary in AuthenticationProperties is designed to store state values that persist throughout the authentication process. This can be useful for scenarios where you need to track custom data related to the authentication session, such as user-specific metadata or temporary flags.

      For example, suppose you are building a weather app, and the user selects a weather location before signing in. You can store this information in the Items dictionary and retrieve it later after the user logs in:

      var items = new Dictionary<string, string?>
      {
          ["weather_location"] = "Antwerp, Belgium"
      };
      
      return Challenge(
          properties: new AuthenticationProperties(items)
          {
              RedirectUri = "/home"
          },
          authenticationSchemes: "oidc");
      

      In this example, the Challenge method initiates the authentication process using the “oidc” scheme. A custom key/value pair ("weather_location": "Antwerp, Belgium") is added to the Items dictionary, which will be carried along through the authentication flow.

      Later, after the user logs in, you can access this data by inspecting the AuthenticationProperties associated with the current user, for example, in Razor Pages. Note that the method name AuthenticateAsync may be misleading: it is used to retrieve information for the current user and not to trigger authentication (which would be done using the ChallengeAsync method).

      public class WeatherModel : PageModel
      {
          public string WeatherLocation { get; private set; }
      
          public async Task<IActionResult> OnGet()
          {
              var authResult = await HttpContext.AuthenticateAsync();
              var authProperties = authResult?.Properties;
      
              if (authProperties?.Items.TryGetValue("weather_location", out var weatherLocation) == true)
              {
                  Weather = RetrieveWeatherForLocationAsync(weatherLocation);
              }
      
              return Page();
          }
      }
      

      Nice! This approach allows you to transfer the user’s selected weather location through the authentication process and use it in your Razor Pages to enhance the user experience in your weather app.

      Note that while the Items dictionary is a convenient way to pass small amounts of data through the authentication process, it is not intended to serve as a session storage mechanism. The data stored in the Items dictionary is often roundtripped to the identity provider, which in may have a limit on the size of this parameter. If you need to store and carry more than one or a few key-value pairs through the authentication flow, consider using other storage mechanisms to keep the state, such as sessions or TempData.

      External identity providers will not be able to see the contents of the Items dictionary. While data is serialized and typically added to the state query string parameter, it is encrypted using ASP.NET Core Data Protection and only readable by your own application. We recommend always configuring Data Protection in your client applications!

      The state parameter may be part of the query string sent to the authorization endpoint, but if you are using Pushed Authorization Requests (PAR) it will be sent to the identity provider using a back channel to prevent authorization parameters being seen or tampered with - even if they are encrypted by default.

      Using AuthenticationProperties.Parameters in your application

      The Parameters dictionary in AuthenticationProperties is used to pass additional data to the authentication handler during the authentication process. This is particularly useful when you need to send custom parameters to an external identity provider or modify the behavior of the authentication flow.

      For example, suppose you are integrating with an OpenID Connect provider and want to pre-fill the username field on the login page by passing a login_hint parameter. You can achieve this by adding the parameter to the Parameters dictionary:

      var parameters = new Dictionary<string, object?>
      {
          ["login_hint"] = "user@example.com"
      };
      
      return Challenge(
          properties: new AuthenticationProperties
          {
              RedirectUri = "/profile",
              Parameters = parameters
          },
          authenticationSchemes: "oidc");
      

      In this example, the Challenge method initiates the authentication process using the “oidc” scheme. The login_hint parameter is added to the Parameters dictionary, which is then passed along to any authentication events or handlers in your ASP.NET Core pipeline. For example, you could consume the login_hint parameter in the OnRedirectToIdentityProvider of your OpenIdConnectOptions:

      builder.Services
          .AddAuthentication(options =>
          {
              options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
              options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
          })
          .AddCookie(options =>
          {
              options.Cookie.Name = "AcmeCorp.WeatherApp";
          })
          .AddOpenIdConnect(options =>
          {
              // ...
      
              options.Events.OnRedirectToIdentityProvider = async context =>
              {
                  if (context.Properties.Parameters.TryGetValue("login_hint", out var loginHint)
                  {
                      Logger.LogInformation("Setting login hint to {LoginHint}", loginHint);
                  }
              
                  await Task.FromResult(0);
              };
              
              // ...
          });
      

      Note that the Parameters dictionary is available in the event callback, but changes you make to this collection will not be reflected in the redirect to the identity provider. As we’ll see later in this post, you’ll need to use the ProtocolMessage property on the context object here to update any query parameters sent to the identity provider.

      The identity provider can use the login_hint parameter to pre-fill the username field on the login page, improving the user experience by reducing the information the user needs to enter manually. If you’re using Duende IdentityServer, you’ll find the UI templates come with a login page in which the login hint is consumed from the authorization request parameters:

      private async Task BuildModelAsync(string? returnUrl)
      {
          // ...
              
          var context = await _interaction.GetAuthorizationContextAsync(returnUrl);
          if (context?.IdP != null && await _schemeProvider.GetSchemeAsync(context.IdP) != null)
          {
              // ...
      
              Input.Username = context.LoginHint;
          
              // ...
          }
      
          // ...
      }
      

      The authorization context here has convenience properties for many known parameters like tenant (in the acr parameter), login_hint, prompt modes, and more. Custom parameters can be accessed using the Parameters property:

      var customParameter = context.Parameters["custom-parameter"];
      

      Keep in mind that the Parameters dictionary is not encrypted or protected like the Items dictionary. It is intended to pass data between your application and the authentication handler, and its contents may be visible to external systems. Use it only for non-sensitive data or data required by the identity provider.

      Note that while the Parameters dictionary is sent to the identity provider for the OpenIdConnectHandler, this may not be true for all authentication handlers available in ASP.NET Core. An example is the GoogleHandler, which only sends specific well-known parameters such as login_hint, prompt, and approval_prompt.

      Providing additional information to an OpenID Connect identity provider

      In the previous section, we saw how the AuthenticationProperties.Parameters dictionary can flow data between call sites in the ASP.NET Core authentication pipeline. There are two more ways to do this, at least in the case of the OpenIdConnectHandler:

      • Using the ProtocolMessage.Parameters dictionary in an event callback like OnRedirectToIdentityProvider
      • Using the AdditionalAuthorizationParameters dictionary in OpenIdConnectOptions (in .NET 9+)

      As a general rule of thumb, I’d recommend using AdditionalAuthorizationParameters when a static parameter value has to be added when redirecting to the identity provider, and ProtocolMessage.Parameters when the parameter’s value must differ based on custom logic.

      Returning to the previous section example, you could consume the login_hint parameter in the OnRedirectToIdentityProvider of your OpenIdConnectOptions, and update its value in ProtocolMessage.Parameters:

      .AddOpenIdConnect(options =>
      {
          // ...
      
          // Add application_type query string parameter when redirecting to the identity provider
          options.AdditionalAuthorizationParameters.Add("application_type", "demo");
      
          // ...
      
          options.Events.OnRedirectToIdentityProvider = async context =>
          {
              // Append #external if login hint domain is not example.com
              if (context.Properties.Parameters.TryGetValue("login_hint", out var loginHint)
                  && loginHint != null
                  && !loginHint.ToString()!.EndsWith("@example.com"))
              {
                  context.ProtocolMessage.Parameters["login_hint"] = loginHint + "#external";
              }
          
              await Task.FromResult(0);
          };
          
          // ...
      });
      

      Conclusion

      In this post, we explored the AuthenticationProperties class in ASP.NET Core and its two key dictionaries: Items and Parameters. We saw how Items can carry state throughout the authentication process while Parameters allow passing additional data to authentication handlers or identity providers. We also discussed OpenID Connect-specific options like ProtocolMessage.Parameters and AdditionalAuthorizationParameters for customizing authentication flows.

      Using these features, you can build more flexible authentication flows that support your application’s needs.

      What are your thoughts on using AuthenticationProperties in your applications? Let us know in the comments below!

      Duende logo

      Products

      • IdentityServer
      • IdentityServer for Redistribution
      • Backend for Frontend (BFF)
      • IdentityModel
      • Access Token Management
      • IdentityModel OIDC Client

      Community

      • Documentation
      • Company Blog
      • GitHub Discussions

      Company

      • Company
      • Partners
      • Training
      • Quickstarts
      • Careers
      • Contact

      Subscribe to our newsletter

      Stay up-to-date with the latest developments in identity and access management.

      Copyright © 2020-2025 Duende Software. All rights reserved.

      Privacy Policy | Terms of Service