Azure AD tokens (ID tokens, access tokens, and SAML tokens) by default last one hour. Asp.Net and Asp.Net Core Middleware sets their authentication ticket to the expiration of these tokens by default. If you do not want your web application to kick the user out redirecting them to Azure AD to sign-in again, you can customize the Middleware authentication ticket.

This can also help resolve AJAX issues (getting CORS error to login.microsoftonline.com) where your app is both a Web App and Web API.


For Asp.Net…

In most cases within your Startup.Auth.cs under ConfigureAuth, you should have a line that says “app.UseCookieAuthentication()”

Update it so that it looks something like this… (This should work for all token types)

app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
  CookieManager = new Microsoft.Owin.Host.SystemWeb.SystemWebChunkingCookieManager(),
  Provider = new CookieAuthenticationProvider()
  {
    OnResponseSignIn = (context) =>
    {
      context.Properties.ExpiresUtc = DateTimeOffset.UtcNow.AddHours(12);
    }
  }
});

You should also decouple the token lifetime from the Web App…

app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                    UseTokenLifetime = false,

Asp.Net Core…

In Asp.Net Core, we essentially need to add the OnTokenValidated event to update the ticket properties to set when the ticket will expire before it decides to redirect to Azure AD to sign-in again.

services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
    // decouple the token lifetime from the Web App
    options.UseTokenLifetime = false;

    // other configurations...
    // ...

    var onTokenValidated = options.Events.OnTokenValidated;
    options.Events ??= new OpenIdConnectEvents();
    options.Events.OnTokenValidated = async context =>
    {
        await onTokenValidated(context);
        context.Properties.ExpiresUtc = DateTimeOffset.UtcNow.AddHours(12);
    };
});

Below are a few examples on how to do this…

If you’re using the following similar code to add Azure AD authentication…

services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
  .AddAzureAD(options => Configuration.Bind("AzureAd", options))

Then add the following…

services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
  // decouple the id_token lifetime from the Web App
  options.UseTokenLifetime = false;

  //…

    var onTokenValidated = options.Events.OnTokenValidated;
    options.Events ??= new OpenIdConnectEvents();
    options.Events.OnTokenValidated = async context =>
    {
        await onTokenValidated(context);
        context.Properties.ExpiresUtc = DateTimeOffset.UtcNow.AddHours(12);
    };
});

So your configuration would look something like this inside your startup.cs…

public void ConfigureServices(IServiceCollection services)
{
  //...

  services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
    .AddAzureAD(options => Configuration.Bind("AzureAd", options))
    .AddCookie();

  //...

  services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
  {
    // decouple the token lifetime from the Web App
    options.UseTokenLifetime = false;

    //...
    var onTokenValidated = options.Events.OnTokenValidated;
    options.Events ??= new OpenIdConnectEvents();
    options.Events.OnTokenValidated = async context =>
    {
        await onTokenValidated(context);
        context.Properties.ExpiresUtc = DateTimeOffset.UtcNow.AddHours(12);
    };
  });

  //...
}

If you’re using “Microsoft.Identity.Web” to add your Azure AD configuration, then you could update your code to look something like this…

//…
using Microsoft.Identity.Web;
//…
public class Startup
{
  // ...
  public void ConfigureServices(IServiceCollection services)
  {
    // ...
    services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
      .AddMicrosoftIdentityWebApp(options =>
      {
        Configuration.Bind("AzureAD", options);

        // decouple the token lifetime from the Web App
        options.UseTokenLifetime = false;

        var onTokenValidated = options.Events.OnTokenValidated;
        options.Events ??= new OpenIdConnectEvents();
     
        options.Events.OnTokenValidated = async context =>
        {
            await onTokenValidated(context);
            context.Properties.ExpiresUtc = DateTimeOffset.UtcNow.AddHours(12);
        };
      });
    // ...
}			

If you’re implementing your own custom OpenIdConnectOptions to configure Azure AD authentication, then add the following…

services.Configure<OpenIdConnectOptions>(options =>
{
  //…
  options.Events.OnTokenValidated = async context =>
  {
    context.Properties.ExpiresUtc = DateTimeOffset.UtcNow.AddHours(12);
  };
});

If you’re integrating a Asp.Net Core WS-Fed application, then it might look something like this…

public void ConfigureServices(IServiceCollection services)
{
  services.AddAuthentication(WsFederationDefaults.AuthenticationScheme)  
    .AddCookie()
    .AddWsFederation(options =>
    {
      options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;

      // decouple the token lifetime from the Web App
      options.UseTokenLifetime = false;

      // MetadataAddress for your Azure Active Directory instance.
      options.MetadataAddress = "https://login.microsoftonline.com/common/federationmetadata/2007-06/federationmetadata.xml";

      // Wtrealm is the app's identifier in the Active Directory instance.
      // For ADFS, use the relying party's identifier, its WS-Federation Passive protocol URL:
      options.Wtrealm = "https://localhost:44307/";

      // For AAD, use the Application ID URI from the app registration's Overview blade:
      options.Wtrealm = "https://contoso.onmicrosoft.com/wsfedapp";

      // Set the Authentication Ticket to expire at a custom time      
      var onTokenValidated = options.Events.OnTokenValidated;
      options.Events ??= new OpenIdConnectEvents();
      
      options.Events.OnSecurityTokenValidated = async context =>
      {
        context.Properties.ExpiresUtc = DateTimeOffset.UtcNow.AddHours(12);
      }

More Information…

Notice that these are actually setting the “Ticket” expiration. You can set this expiration to whatever you like.

Keep in mind if you’re modifying these expirations, the user will continue to access your web app even if they have been deleted or disabled in Azure AD.

Leave a Comment