Coordinating AD FS 2012 R2 token lifetimes to reduce logon prompts, enforce revocation and limit session duration over public networks

Back in February, I posted a question on the Geneva forum about Adjusting token lifetimes at the Web Application Proxy (WAP) for external access:

Does the Web Application Proxy or AD FS have any separate controls for adjusting token lifetimes to a different value via WAP than directly at AD FS? I can see there’s a session cookie for EdgeAccessCookie that WAP issues but this seems to be entirely undocumented at present. I’ve poked around in C:\Windows\ADFS\Config\microsoft.identityServer.proxyservice.exe.config (also undocumented as far as I can tell) but I’m not finding anything there either. We used to have some of these controls (sort of) with TMG/UAG. Are they totally gone now? With the AD FS Proxy this was less of an issue because it was only publishing AD FS but this is something that I’d hope to be able to control with a Reverse Proxy. Any ideas?

I didn’t get any replies, but after carrying out some tests of my own, I noticed the EdgeAccessCookie, and found a bit of information on TechNet:

After the user is authenticated, the AD FS server issues a security token, the ‘edge token’, containing the following information and redirects the HTTPS request back to the Web Application Proxy server:

  • The resource identifier that the user attempted to access.
  • The user’s identity as a user principal name (UPN).
  • The expiry of the access grant approval; that is, the user is granted access for a limited period of time, after which they are required to authenticate again.
  • Signature of the information in the edge token.

Web Application Proxy receives the redirected HTTPS request from the AD FS server with the edge token and validates and uses the token as follows:

  • Validates that the edge token signature is from the federation service that is configured in the Web Application Proxy configuration.
  • Validates that the token was issued for the correct application.
  • Validates that the token has not expired.
  • Uses the user identity when required; for example to obtain a Kerberos ticket if the backend server is configured to use Integrated Windows authentication.

If the edge token is valid, Web Application Proxy forwards the HTTPS request to the published web application using either HTTP or HTTPS.

This quickly became one of those things where there was insufficient documentation and limited project time, so I had to put this inquiry on hold. Then in July, I posted a question on the Application Proxy blog (a great resource), to see if this is something that they planned to document. The response that I got from Ian Parramore was unexpected and pleasing:

In terms of the EdgeAccessCookie and overall auth flow and architecture I agree we should definitely do something on this. It’s something we have talked about here but we’ve been trying to prioritise our content based on where we’ve see an immediate need. I’ll probably start to draft something in the next few weeks.

From a timeout perspective this is a topic we’ve been having some internal discussions about so it’s definitely an area we’re looking at. There are already timeouts you can control as the WAP token has it’s own defined lifetime in ADFS – you can access the WAP RPT properties using the Get-AdfsWebApplicationProxyRelyingPartyTrust PowerShell cmdlet. I’ll make sure I include some details on this and other relevent token lifetimes in the auth flow blog.

It turns out there is a set of six of the these AdfsWebApplicationProxyRelyingPartyTrust cmdlets:

Set-AdfsWebApplicationProxyRelyingPartyTrust

Add-AdfsWebApplicationProxyRelyingPartyTrust

Disable-AdfsWebApplicationProxyRelyingPartyTrust

Enable-AdfsWebApplicationProxyRelyingPartyTrust

Get-AdfsWebApplicationProxyRelyingPartyTrust

Remove-AdfsWebApplicationProxyRelyingPartyTrust

I suspect I’ve failed to notice them previously because these WAP configuration controls are actually within the AD FS cmdlets. To illustrate, we also have these cmdlets that ship with the WAP:

Add-WebApplicationProxyApplication

Get-WebApplicationProxyApplication

Get-WebApplicationProxyAvailableADFSRelyingParty

Get-WebApplicationProxyConfiguration

Get-WebApplicationProxyHealth

Get-WebApplicationProxySslCertificate

Install-WebApplicationProxy

Remove-WebApplicationProxyApplication

Set-WebApplicationProxyApplication

Set-WebApplicationProxyConfiguration

Set-WebApplicationProxySslCertificate

Update-WebApplicationProxyDeviceRegistration

(and note this great WAP PowerShell cheat sheet, also from the Application Proxy blog team).

Anyway… if we look at the parameters of the AdfsWebApplicationProxyRelyingPartyTrust cmdlets, sure enough there is a TokenLifetime setting, and this TokenLifetime setting is how we control the “edge token” (referred to here as “WAP lifetime”). Confusingly, when I first tried this out, by setting the WAP lifetime to two minutes, I couldn’t see any effect, but there is a perfectly reasonable explanation for this, as explained by Ian in the comments on the post that I originally commented on.

There are 2 key timeouts involved here:-

WAP token lifetime – when this expires the client will be redirected to adfs for a new token. If the adds sso cookie is still valid the new wasp token will be issued without any user intervention (unless the relevant rpt requires auth for each token request.

Adfs sso cookie lifetime – this is an adfs property and determines how long the client can obtain tokens from the adfs server without reauthentication.

If you’re expecting the client to reauth after 2 minutes then it’s not going to happen due to the adfs sso cookie still being valid.

This is great news that the WAP lifetime works in line with the AD FS Web SSO lifetime. As I’ve noted before, controlling access with two different pipelines and timeouts can get pretty confusing. But this is only 2/3 of the story. We also have a Relying Party Trust token lifetime, and we need to make sure that all three token lifetimes work together to create the experience we’re after, inside and outside of the network. In fact, we already know that focusing solely on these three token lifetimes is insufficient, as there are a load of default timeouts, form digest settings, clock skew and effects from other infrastructure in between a user and AD FS or the Relying Party. Any of these settings/lifetimes can have an impact here, but it’s still worth treating those as non-factors for the purposes of understanding how these three token lifetimes work together. This is a complicated topic that will surely take some time for the Application Proxy team to document well, so I’m going to share my test results in the mean time, as I think these can be used as points of reference in order to validate that token lifetime settings are achieving what we’re after.

Disclaimer
Although I’ve put a lot of effort in to validating the results that I’ve measured and the interpretations I put forward here, there’s a risk I may have some of this wrong, since I’m working backwards from results to a conceptual framework. Please use this as a guide for choosing lifetimes, then validate that this configuration behaves as you expect.

About the tests

Test values

In each of these test scenarios, I change the token lifetimes to “low”, “medium” and “high” values of two minutes, five minutes and ten minutes. These values have been selected for testing speed and because they illustrate the changes well – not because ten minutes is actually a high token lifetime.

The six tests represent the six permutations of relative values among these three settings. Some of these scenarios don’t make a lot of sense at a glance, but I include those results because it’s important to understand how these possible misconfigurations will operate if you should find an environment in that state. And some of these scenarios may emerge precisely because people are unaware that there are controls for the WAP lifetime (or any of these lifetimes for that matter).

Terminology

In the rest of this post, I refer to the “edge token” as the “WAP token lifetime”, or “WAP lifetime” for brevity, in line with the Set-AdfsWebApplicationProxyRelyingPartyTrust -TokenLifetime command. Irrespective of what this token lifetime is really called, it is stored in the EdgeAccessCookie. When I refer to the cookie, I mean the storage rather than the token. When I refer to the lifetime I mean the token lifetime.

In the results column heading of the spread sheet below, I use some terms with a specific intended meaning:

  • Settings:
    • WAP Token Lifetime: Set-AdfsWebApplicationProxyRelyingPartyTrust -TokenLifetime value.
    • Web SSO Lifetime: Set-AdfsProperties -SSOLifetime value.
    • RP Trust Token Lifetime: Set-ADFSRelyingPartyTrust -TokenLifeTime (minus LogonTokenCacheExpirationWindow value). Think of it as the effective ADFSRelyingPartyTrust -TokenLifeTime.
  • Internal results:
    • Internal Revocation Window: the duration (in minutes) after disabling an account before a user will lose access to a Relying Party, when that user is attempting to access a resource from inside the corporate network.
    • Internal SSO Duration: the duration (in minutes) a user can access other AD FS Relying Parties inside their corporate network without receiving a logon prompt. Note: the Web SSO setting only applies when this AD FS farm authenticates the user against AD DS (AD FS is not trusting some other Claims Provider for this user).
    • Internal Timeout: the duration (in minutes) a user can use a Relying Party before having to re-authenticate with AD FS, when that user is inside the corporate network.
  • External results:
    • External Revocation Window: the duration (in minutes) after disabling an account before a user will lose access to a Relying Party, when that user is attempting to access a resource from outside the corporate network.
    • External SSO Duration: the duration (in minutes) a user can access other AD FS Relying Parties from outside their corporate network without receiving a logon prompt. Note: the Web SSO setting only applies when this AD FS farm authenticates the user against AD DS (AD FS is not trusting some other Claims Provider for this user).
    • External Timeout:  the duration (in minutes) a user can use a Relying Party before having to re-authenticate with AD FS, when that user is outside the corporate network.

LogonTokenCacheExpirationWindow

Each of the Relying Party Trust token lifetime settings is skewed forward by +10. This is because I have SharePoint’s SPSecurityTokenServiceConfigLogonTokenCacheExpirationWindow set to “10”, which instructs the SharePoint Security Token Service to invalidate a SAML token ten minutes before it expires (so a user can obtain a fresh token without disruption).  As you will see in the first example, a Relying Party’s token lifetime will expire after 10 minutes even though the Set-ADFSRelyingPartyTrust -TokenLifetime value is set to “20”.

Configuration scripts for the six test scenarios

Scenario 1: Low WAP lifetime, medium Web SSO lifetime, high RP trust lifetime

#WAP token lifetime = 2 minutes
#AD FS Web SSO Lifetime = 5 minutes
#RP Trust lifetime = 20 (minutes, the default, which actually expires after 10 per a `
LogonTokenCacheExpirationWindow of 10)
Set-AdfsWebApplicationProxyRelyingPartyTrust -TokenLifetime 2
Set-AdfsProperties -SSOLifetime "5"
Get-ADFSRelyingPartyTrust | Where-Object {$_.name -like "https://*"} | ForEach-Object `
{Set-ADFSRelyingPartyTrust -TargetName $_.name -TokenLifeTime 20}
$RPTrustsTL20 = Get-ADFSRelyingPartyTrust | Where-Object {$_.TokenLifetime -like 20}
$RPTrustsTL20.Name

Scenario 2: Low WAP lifetime, medium RP trust lifetime, high Web SSO lifetime

#WAP token lifetime = 2 minutes
#AD FS Web SSO Lifetime = 10 minutes
#RP Trust lifetime = 15 (minutes, the default, which actually expires after 5 per a `
LogonTokenCacheExpirationWindow of 10)
Set-AdfsWebApplicationProxyRelyingPartyTrust -TokenLifetime 2
Set-AdfsProperties -SSOLifetime "10"
Get-ADFSRelyingPartyTrust | Where-Object {$_.name -like "https://*"} | ForEach-Object `
{Set-ADFSRelyingPartyTrust -TargetName $_.name -TokenLifeTime 15}
$RPTrustsTL15 = Get-ADFSRelyingPartyTrust | Where-Object {$_.TokenLifetime -like 15}
$RPTrustsTL15.Name

Scenario 3: Low RP trust lifetime, medium WAP lifetime, high Web SSO lifetime

#WAP token lifetime = 5 minutes
#AD FS Web SSO Lifetime = 10 minutes
#RP Trust lifetime = 12 (minutes, the default, which actually expires after 2 per a `
LogonTokenCacheExpirationWindow of 10)
Set-AdfsWebApplicationProxyRelyingPartyTrust -TokenLifetime 5
Set-AdfsProperties -SSOLifetime "10"
Get-ADFSRelyingPartyTrust | Where-Object {$_.name -like "https://*"} | ForEach-Object `
{Set-ADFSRelyingPartyTrust -TargetName $_.name -TokenLifeTime 12}
$RPTrustsTL12 = Get-ADFSRelyingPartyTrust | Where-Object {$_.TokenLifetime -like 12}
$RPTrustsTL12.Name

Scenario 4: Low Web SSO lifetime, medium WAP lifetime, high RP trust lifetime

#WAP token lifetime = 5 minutes
#AD FS Web SSO Lifetime = 2 minutes
#RP Trust lifetime = 20 (minutes, the default, which actually expires after 10 per a `
LogonTokenCacheExpirationWindow of 10)
Set-AdfsWebApplicationProxyRelyingPartyTrust -TokenLifetime 5
Set-AdfsProperties -SSOLifetime "2"
Get-ADFSRelyingPartyTrust | Where-Object {$_.name -like "https://*"} | ForEach-Object `
{Set-ADFSRelyingPartyTrust -TargetName $_.name -TokenLifeTime 20}
$RPTrustsTL20 = Get-ADFSRelyingPartyTrust | Where-Object {$_.TokenLifetime -like 20}
$RPTrustsTL20.Name

Scenario 5: Low RP trust lifetime, medium Web SSO lifetime, high WAP lifetime

#WAP token lifetime = 10 minutes
#AD FS Web SSO Lifetime = 5 minutes
#RP Trust lifetime = 12 (minutes, the default, which actually expires after 2 per a `
LogonTokenCacheExpirationWindow of 10)
Set-AdfsWebApplicationProxyRelyingPartyTrust -TokenLifetime 10
Set-AdfsProperties -SSOLifetime "5"
Get-ADFSRelyingPartyTrust | Where-Object {$_.name -like "https://*"} | ForEach-Object `
{Set-ADFSRelyingPartyTrust -TargetName $_.name -TokenLifeTime 12}
$RPTrustsTL12 = Get-ADFSRelyingPartyTrust | Where-Object {$_.TokenLifetime -like 12}
$RPTrustsTL12.Name

Scenario 6: Low Web SSO lifetime, medium RP trust lifetime, high WAP lifetime

#WAP token lifetime = 10 minutes
#AD FS Web SSO Lifetime = 2 minutes
#RP Trust lifetime = 15 (minutes, the default, which actually expires after 5 per a `
LogonTokenCacheExpirationWindow of 10)
Set-AdfsWebApplicationProxyRelyingPartyTrust -TokenLifetime 10
Set-AdfsProperties -SSOLifetime "2"
Get-ADFSRelyingPartyTrust | Where-Object {$_.name -like "https://*"} | ForEach-Object `
{Set-ADFSRelyingPartyTrust -TargetName $_.name -TokenLifeTime 15}
$RPTrustsTL15 = Get-ADFSRelyingPartyTrust | Where-Object {$_.TokenLifetime -like 15}
$RPTrustsTL15.Name

Test Results for the six scenarios

Token Lifetime Test Results 2

The most evident finding: SSO duration and revocation

The Internal and External SSO durations have been shaded darker in the results above, and you will note there is no helpful language for these results – just a value. That is because the Web SSO lifetime is a sort of master value for the service. It can effectively extend a Relying Party’s session lifetime or refresh WAP tokens if it is set to a higher value, but neither the WAP nor RP lifetimes will ever change the SSO duration. The only thing that can over-ride Web SSO is disabling an account in Active Directory. Web SSO respects revocation. To this end, you will note that the Set-AdfsProperties -SSOLifetime setting is perfectly aligned with SSO duration in the results above, both inside and outside the network.

The six remaining interpretations focus on how revocation windows and timeouts can be predictably altered by a chosen coordination of these three values, inside and outside of a corporate network.

Interpreting scenario 1: Low WAP lifetime (2), medium Web SSO lifetime (5), high RP trust lifetime (10)

Internal timeout

Inside the corporate network, the RP Trust lifetime will outlast the Web SSO lifetime since the RP Trust lifetime is longest. More precisely, each RP Trust lifetime is independent. We may encounter a scenario where a user requests a second Relying Party within the five minute Web SSO window – say at 4:20 after the user first signed on. In this scenario, the first Relying Party would timeout after ten minutes. The second Relying Party would timeout 14:20 after the user signed-on. Timeout could be as high as fifteen minutes, if we conceive of it as the time elapsed since sign-on. If we think of it as time elapsed since the Web Application is requested then timeout will match the RP Trust lifetime. Put a slightly different way, AD FS will prompt a user to sign-on again when the RP Trust lifetime expires, because the Web SSO lifetime will have already expired.

External timeout

Outside the corporate network, the Web SSO lifetime becomes the most important consideration for understanding session timeout, because the WAP token will be automatically refreshed by Web SSO until Web SSO times out. But that combined WAP + Web SSO lifetime will always be less than the ten minute RP Trust lifetime, so the high RP Trust lifetime does not factor in to this external timeout. Even if a fresh WAP token is issued at 4:59 in to the Web SSO lifetime, a user will still need to sign-on again at 6:59 when the last two minute WAP lifetime expires.

Internal revocation

AD FS can only revoke a disabled user’s access when that user needs a new token. If a user is inside the corporate network they will retain access until their RP Trust lifetimes expire. Remember that if these tokens were issued at different times in the Web SSO lifetime, they may not expire concurrently, but both will predictably expire within each separate RP Trust lifetime. No disabled account will retain access inside the corporate network for longer than ten minutes.

External revocation

Outside the corporate network,the WAP lifetime becomes incredibly useful. We know that external access will be revoked from disabled users within a two minute window because the WAP forces the user to request a new token from AD FS every time the WAP lifetime expires for a Relying Party. Even though an enabled user will retain access for 5-7 minutes after sign-on via Web SSO, a disabled user will never retain access for more than two minutes.

Interpreting scenario 2: Low WAP lifetime (2), medium RP trust lifetime (5), high Web SSO lifetime (10)

Internal timeout

In this second scenario, the Web SSO lifetime now outlasts the RP Trust lifetime. This means internal timeout isn’t principally dictated by RP Trust lifetime anymore. Whenever an RP Trust lifetime expires within the Web SSO lifetime it will be automatically refreshed. Although my five minute RP Trust lifetime appears to be shortened, I will retain my session for longer than the ten minutes I had in scenario #1 if I am continuing to use the session in the 6-10 minute window. For instance, if I use my RP for four minutes after signing on, then refresh my session at 9:59 in to the Web SSO lifetime, I will time out 14:59 after initiating my session.

External timeout

This high Web SSO lifetime also extends external timeout. 5-7 minutes in scenario #1 becomes 10-12 minutes. Although this pattern is strictly the same as scenario #1, this high value for Web SSO applies equally inside and outside the network, so it may negate some of the benefits of having an independent WAP lifetime. For instance, if Web SSO was set to eight hours (the default value) and WAP lifetime was set to sixty minutes, the WAP lifetime will have a minor impact on timeout, mostly limiting its benefit to revocation enforcement. It won’t do anything to limit session duration on low-trust machines (internet cafe, etc.).

Internal revocation

Increasing the Web SSO value does not have an impact on revocation per se, but decreasing the RP Trust lifetime does. It shortens the revocation window for a disabled user inside the corporate network to <5 minutes.

External revocation

The external revocation window is controlled by the shortest token lifetime, so scenario #2 has has the same two minute window as scenario #1, because the WAP lifetime is lowest.

Interpreting scenario 3: Low RP trust lifetime (2), medium WAP lifetime (5), high Web SSO lifetime (10)

These results reveal that the WAP lifetime has no effect when the RP Trust lifetime is set to a lower value, and the Web SSO lifetime is higher. When the WAP lifetime has no effect, the timeout and revocation durations are the same internally and externally. While this is by no means invalid, keep in mind that a more elegant experience may be achievable with a scenario that uses the WAP lifetime setting (scenarios #1, #2 and #4). But having said that, remember that when different Relying Parties have different token lifetimes, this condition may emerge for a subset of trusts.

Internal and external timeout

As in scenario #2, Web SSO lifetime outlasts RP Trust lifetime, but by an even more significant margin. The RP trust lifetime may be refreshed four times within the Web SSO lifetime, and an actual session may persist for up to 11:59.

Internal and external revocation

Access is always revoked within two minutes of disabling a user’s account in this scenario, since the low RP trust lifetime triggers Web SSO, at which point AD FS will only issue a fresh token to an enabled user.

Interpreting scenario 4: Low Web SSO lifetime (2), medium WAP lifetime (5), high RP trust lifetime (10)

In this configuration the Web SSO lifetime is set to a lower value than the WAP Token Lifetime or the RP Trust Token Lifetime, so Web SSO will never refresh an RP Trust lifetime or WAP lifetime. But it will still enable SSO to other Relying Parties within the two minute window, as expected. This scenario follows the same pattern as scenarios #1 and #2.

Internal timeout

Internal timeout is dictated by RP Trust lifetime. Any given session will not outlast the RP Trust lifetime, but remember that if a user visits a second Relying Party after 1:59, that second RP Trust lifetime will expire 11:59 after that user first signed-on. The first RP Trust times out at 10:00.

External timeout

External sessions will timeout after five minutes, because the WAP lifetime is shorter than the RP Trust lifetime, and Web SSO will have already expired.  If a user visits a second Relying Party after 1:59, that second WAP lifetime will expire 6:59 after that user first signed-on.

Internal revocation

Internal revocation duration follows the same pattern as in scenarios #1 and #2. A user inside the corporate network will retain access for up to 10:00 (the remaining RP Trust lifetime) after their account is disabled. Keep in mind that RP Trust lifetimes may vary, and remaining time for any given RP Trust will depend upon when that Relying Party was first requested.

External revocation

External revocation duration also follows the same pattern as in scenarios #1 and #2. An external user will retain access for up to 5:00 (the remaining WAP lifetime) after their account is disabled. As with RP Trust lifetimes for internal users, keep in mind that these remaining WAP lifetimes for external users may be staggered across Relying Parties if they were requested at different times within the Web SSO Lifetime.

Interpreting scenario 5: Low RP trust lifetime (2), medium Web SSO lifetime (5), high WAP lifetime (10)

As in scenario #3, this configuration sets the RP Trust lifetime lower than the WAP lifetime, so the WAP lifetime has no effect. Remember that this means the timeout and revocation durations are the same internally and externally. When considering these settings for one Relying Party in isolation it may be difficult to see the value in this configuration, but these conditions may emerge for a subset of trusts if RP Trust lifetimes vary across Relying Parties.

Internal and external timeout

As in scenarios #2 and #3, Web SSO lifetime outlasts RP Trust lifetime, but by a less significant margin. In this scenario the RP trust lifetime may be refreshed twice within the Web SSO lifetime, and an actual session may persist for up to 6:59.

Internal and external revocation

As in scenario #3, access is always revoked within two minutes of disabling a user’s account, since the low RP Trust lifetime triggers Web SSO, at which point AD FS will only issue a fresh token to an enabled user.

Interpreting scenario 6: Low Web SSO lifetime (2), medium RP trust lifetime (5), high WAP lifetime (10)

As with scenarios #3 and #5, this configuration sets the RP Trust lifetime lower than the WAP lifetime, so the WAP lifetime has no effect. Timeout and revocation durations are the same internally and externally accordingly.

Internal and external timeout

As in scenarios #1 and #4, RP Trust lifetime outlasts the Web SSO lifetime, so any given session will not outlast the RP Trust lifetime. However, session expiration may be staggered if multiple Relying Parties were requested within the Web SSO lifetime.The first Relying Party lifetime would expire 5:00 after sign-on, while a second Relying Party accessed 1:59 in to the Web SSO lifetime would expire at 6:59.

Internal and external revocation

Access is always revoked within five minutes of disabling a user’s account, since the WAP lifetime has no effect. In this scenario the RP Trust lifetime simply expires. Revocation doesn’t need to be enforced. But when a revoked user next tries to log in, they will see a “bad username/password” response. This is slightly different to most (but not all) of the other revocation experiences.

Further interpretation

Generally, these three settings will be configured with four concerns in mind:

  1. Revoking access for disabled users.
  2. Limiting session duration from public machines (like an internet cafe). We want to limit the risk of a user wandering away from a public machine while logged on.
  3. Reducing repetitious/annoying log in prompts for enabled users who simply want to get their work done.
  4. Working with or around other timeout settings, for instance if form data might be lost when a session expires.

The second and third of these requirements are often at odds with each other. But in my view there is some important corollary considerations that accompany each of these concerns:

  1. Typically, revoking access to AD FS-secured resources for disabled users is less of a concern inside a controlled corporate environment than it is over public networks. This is because inside a corporate network, the organisation has other ways of disabling access – like by taking away the computer, revoking network access or marching the user outside of the building. This is where the WAP lifetime becomes very useful, as it is primarily a tool for accelerating revocation to some shorter duration than the remaining RP Trust lifetime, when that user is outside the corporate network.
  2. The WAP lifetime is also useful for reducing external timeout while allowing longer sessions internally (in order to improve the user experience). However, the WAP lifetime will be automatically refreshed within the Web SSO lifetime, so the total allowable session duration should be calculated by adding the two values together. Also remember that if Web SSO is lowered too much, then users will need to re-authenticate when accessing multiple Web Applications.
  3. For environments that operate with mostly Windows clients, Integrated Windows Authentication can balance out a lot of the disruptiveness of shorter lifetimes – although this is not always a silver bullet. In some cases, the redirection to AD FS to acquire fresh token may be disruptive, even without a logon prompt, and in other cases it may not be possible to reduce token lifetimes aggressively without breaking sessions (think about forms and the other lifetimes I mentioned above).
  4. In some cases the best response to requirements from other timeout settings might be to look at those root causes and make changes outside of AD FS. In these cases, we might have decided that these three AD FS settings have a primary value that other timeouts must respect. This may not be simple, and may introduce development costs, but it may be the best approach. In other cases it would be totally inappropriate and these three settings should bend to accommodate other timeouts.

All told, this requires orchestration and testing, especially when different Relying Parties require different RP Trust lifetimes. This article attempts to provide a framework for understanding how the settings inter-operate with different relative values. Providing generalised guidance about these settings is difficult because each organisation will handle the compromises between user experiential and security concerns differently. In lieu of that generalised guidance, I will add a few more thoughts that may be helpful.

  • Each Web Application has its own EdgeAccessCookie with its own WAP lifetime, but there is one global Set-AdfsWebApplicationProxyRelyingPartyTrust -TokenLifetime value that applies to all published Web Applications. This WAP lifetime starts counting at the same time as the RP Trust lifetime for that Relying Party.
  • If you work in an environment where a single solution spans multiple Relying Parties, it’s possible that something clever will happen on-load that will issue requests to all of the Relying Parties in the solution. For instance, I may browse to my intranet home page, which will surface pictures from my SharePoint MySite Host. If each of those are different Relying Parties, so I need to make sure I’m signed in to both Web Applications in order to prevent broken images, etc. In this scenario, it’s important to align RP Trust lifetimes, on the assumption that our code will trigger a request to all Relying Parties in the solution nearly-concurrently.
  • When viewing these results from a high level, it becomes clear that timing has as much importance as timeout when planning for predictable session expiration, if I conceive of expiration as the time when credentials were provided at sign-on through the moment when my longest-lasting Relying Party times out. As a general formula, this combined session duration can be thought of as:
    • Internal users: [Web SSO duration + RP lifetime remaining in current Relying Party sessions].
    • External users: [Web SSO duration + (the shorter of WAP lifetime or RP lifetime) remaining in the current Relying Party sessions].
  • These are some rules of thumb about revoking access for disabled users:
    • Internal revocation window = RP lifetime remaining after an account is disabled. This may be staggered across Relying Parties with different token lifetimes and different remaining session durations when the account is disabled.
    • External revocation window = (the shorter of WAP lifetime or RP lifetime) remaining after an account is disabled. These may also be staggered as above.
  • SSO duration is strictly determined by the Web SSO lifetime, irrespective of network location or the WAP/RP Trust lifetime settings. It will always allow issuance or renewal of RP Trust and WAP tokens, so long as the account is enabled and the Web SSO lifetime has not expired.
  • The WAP token lifetime must be set to a lower value than the RP lifetime for it to have an effect (as in scenarios #1, #2 and #4). At risk of oversimplifying, I would generally advise sticking to these scenarios. This is a brief summary of how the results of those scenarios can be understood:
    • Scenario #1:  Low WAP lifetime, medium Web SSO lifetime, high RP trust lifetime
      • External access should be subject to frequent revocation checks.
      • External session duration is average.
      • Internal sessions should be long-lasting.
    • Scenario #2: Low WAP lifetime, medium RP trust lifetime, high Web SSO lifetime
      • External access should be subject to frequent revocation checks.
      • External session duration is liberal.
      • Internal sessions should be of average duration.
    • Scenario #4: Low Web SSO lifetime, medium WAP lifetime, high RP trust lifetime
      • External access should be subject to less frequent revocation checks.
      • External session duration is strict.
      • Internal sessions should be long-lasting.
  • Take a minute to think through how your solutions would work with the default settings (which adhere to scenario #3). Is this suitable for you?
    • Eight hours SSO (480 minutes).
    • 50 minute RP (assuming 10 minute forward skew in SharePoint).
    • 60 minute WAP lifetime.

Lastly, don’t forget that other controls can have a part to play in this configuration, such as a device certificate as a second factor, or a smart card, etc. The internal/external convention I’ve focused on here might change if access is controlled differently for trusted devices outside the network.

This post is now exceptionally long, but if you feel that any of this can be clarified or if any of these areas need deeper exploration, post in the comments here and I’ll try to clear things up.

24 thoughts on “Coordinating AD FS 2012 R2 token lifetimes to reduce logon prompts, enforce revocation and limit session duration over public networks”

  1. Ok, so if we really want our uses authentication NOT to expire in a short time, what would be the best settings (i.e. we don’t want ADFS to keep refreshing our security token)? The short interval prevents postbacks from happening after the re-direct back to the ADFS server.

  2. If you’re trying to keep forms alive without redirecting then you need to make sure your relying party trust lifetime and your WAP lifetime are longer than the longest session lifetime that you intend to support. Having said that, you may need to reach a compromise with security stakeholders if this longer session lifetime increases to a value that introduces unacceptable risks (for instance in a kiosk scenario). It’s the usual territory where usability and security need to give and take. Ultimately I can’t tell you what an acceptable value (or values) will be for your requirements. This post aims to detail the outcomes of different combinations of settings so you can predictably achieve what you require, since I don’t think those outcomes are obvious until you’ve started looking at how the settings interact when different values are entered.

  3. Thanks for getting back to me so fast. The fundamental problem we are having is that a user performs data entry. The user then submits the page. 95% of the time the page is submitted as a post-back to the server without a problem. However, users occasionally experience being re-directed back to the ADFS server (for re-authentication), then re-directed back to the page (using IE). The problem in this case is that everything entered by the user is lost and they get frustrated. I have a hack to fix the problem by persisting their data entry values in a cookie, but I would rather resolve this with controlling the trust lifetime. I will be working with MS on this. The docs on ADFS 3.0 are terrible and we are struggling to find a solution. I may try the commands you mentioned above, but again, why didn’t MS include this as part of the ADFS UI?

  4. I agree this isn’t the best-documented facet of AD FS configuration. As I mention here, it’s on the “to do” list for the Application Proxy team to address this, but as you can tell from the complexity of this post it is not an easy topic, and I’m not even trying to address everything (6000 words is a long enough read by any standard). Ultimately, you’re on to the right type of solutions (assuming storing the data in a cookie is acceptable from a security point of view). I think there are various usability tricks that could factor in here, like warning messages embedded on the page, timers, pop-ups, etc. but that stuff starts to drift outside of my skills so I don’t really feel comfortable making suggestions about that. Before doing any of this I would try to find out if I could solve this by setting the token lifetimes to some value that averts most of the 5% of these remaining problems, but when external access is involved that can get tricky. I think the AD FS team shouldn’t really be taking responsibility for these application concerns, but some warnings about what might happen when values are low would be a good start.

    As for why this isn’t in the UI… Good question! 1/3 of it is. But really you need to get comfortable with the PowerShell to be successful with AD FS and the WAP. I suspect that’s the answer you’ll get to that question.

  5. Thanks Tristan. Much appreciated. We will continue to seek a solution. Your article definitely has shed light on some of the inner workings of ADFS.

  6. Hi Tristan. Thank you for such detailed article. I wonder if you have also looked to timeouts on WAP server itself – InactiveTransactionsTimeoutSec and PersistentAccessCookieExpirationTimeSec and how those come in to play. I have non claims-aware publication with kerberos preauthentication and delegation and therefore I think that WAP Token lifetime and RP Trust lifetime doesn’t play role here, however we are experiencing some kind of timeout problem – with both timeouts on WAP set to 15min, after some 7-8 minutes trying to access link in the same page (without refreshing or navigating elsewhere) we get server method failed. Refreshing or navigating to another page solves the problem for next 7-8 minutes. Also, WAP Token Timeout and RP Trust lifetime timeout are 0 by default on freshly installed ADFS, so I wonder what kind of experience is supposed to be in this default configuration.

    Thank you in advance.

  7. Thanks Janis. I’ve never looked in to either of those parameters before and I’m not 100% certain if they are only present in an update to the WAP or if they have always been there. When I originally raised this question on the Application Proxy blog they didn’t mention these cmdlets, so I didn’t realize there were even more knobs and dials than the one that I focused on! I suspect at least the PersistentAccessCookieExpirationTimeSec setting is new based on this KB article (which may be of use beyond explaining that this was introduced in a hotfix). https://support.microsoft.com/en-us/kb/3020813

    Unfortunately I am going to struggle to find the time to test these settings in the immediate future, but if you do get the time I would be interested to know how you get on. Without knowing more about what you’re trying to do this is kind of a stab in the dark, but I would probably focus on InactiveTransactionsTimeoutSec in the first instance. I spotted a post on that setting which suggested increasing the value to 930 solved their problem, where some timeout was 900, but I have only skimmed quickly and really can’t recommend whether any changes to this setting are a good idea without going deeper.

  8. Thanks for the article, that was a really good read.

    I’m now struggling with finding acceptable timeouts for a couple of use cases that I can’t adequately separate. Say we’re using WAP to publish SharePoint.

    In the kiosk scenario, someone logs into a shared PC and into SharePoint using their normal credentials and MFA. All good, they do their work and then close the browser window. Or maybe they forget that they left a window minimised. At any rate, we want the timeout in this scenario to be a couple of hours, let’s say four at the most.

    On the other hand, a staff member logs into the Excel app on his iPad and adds our SharePoint server as a document source. He browses around and opens a spreadsheet, does some work and then saves it. Or he sets up the OneDrive app to sync his My Site. In those scenarios we really don’t want the user prompted for creds over and over. Ideally we want to measure the re-auth time in weeks or months there, or at least no re-auth until their AD password changes. Similar behaviour to Exchange ActiveSync in the mail client on their phone, but with the initial login protected by MFA.

    I can’t for the life of me work our how we’d distinguish between browser-based sessions on shared PCs and apps on semi-trusted BYOD tablets when it comes to setting lifetimes on auth tokens. I’m not even sure where to start. Is this something you’ve run into before and found a neat solution to?

  9. Hi Ryan. Thankfully there is a solution for that. Workplace Joined devices benefit from persistent SSO for seven days by default (as well as having a certificate as a second factor). So you could have the iPad users join their iPads and lower the WAP token lifetime as you see fit for the untrusted device scenarios. You can use either the AD FS Device Registration Service or the Azure AD Device Registration Service (with device writeback in Azure AD Premium and AAD Connect) to deploy the certificates and manage device object creation. AD FS can work with AD DS device objects that have been created by either service. My preference leans towards the Azure AD Premium service these days, as this also support Intune Conditional Access and this is generally the direction of travel, but this does assume you have the Premium licensing in place.

  10. Hello, Thank you for your article. I try to follow your scenario to do testing. I have 1 AD FS 3.0 and 1 proxy server as identity provider. Instead of using sharepoint, I create a .net application as Relying party (follow this http://www.dotnetcurry.com/windows-azure/1158/using-adfs-azure-single-signon-aspnet-mvc). All user must pass though Proxy server to go to AD FS to do authentication. But our result is different from your result. For 6 scenario, WAP Token lifetime does not affect the session time out.

    Combined session duration = Web SSO duration + RP lifetime remaining in current Relying Party sessions

    How you define external user and internal user in your testing case?

  11. I think your description is what I’m saying should happen for scenario 6. I think our results are the same. Because the RP token lifetime expires before the WAP token lifetime, the user gets challenged when the RP token lifetime expires.

    External user = user coming in via WAP in my testing. Internal users resolve to AD FS directly, so the WAP token lifetime does not apply to them. In this scenario the behaviour should be the same internally and externally though.

  12. Sorry for my typo mistake. I mean for all 6 scenarios, combined session duration = Web SSO duration + RP lifetime remaining in current Relying Party sessions ( + sometimes I need to wait for 1 or 2 more minutes to see session expire).

  13. Hmmm… That’s definitely not normal, nor expected. At a guess, that sounds like maybe the external traffic is bypassing the WAP and routing directly to AD FS. If the WAP token lifetime is not having any effect, it’s either higher than the other values or the traffic isn’t actually going via the WAP. Either that or something very strange is happening. If you find out, I would be interested to know!

  14. Fantastic write-up, thanks for taking the time to do this and actually sharing it too!
    With the introduction of Modern Authentication functionality with O365, would you happen to have any information around the “refreshtoken” functionality and how specifically it plays into these scenarios?
    Thanks!

  15. Hi JB. Sorry about the slow reply. The short answer is that it’s a different flow, and it isn’t implemented in AD FS 2012 R2. Modern Authentication implements Open ID Connect, which is a user authentication extension to the OAuth 2.0 authorisation framework. I believe Open ID Connect is expected to be implemented in AD FS 2016, but unfortunately I’ve not spent much time with it yet.

    Specifically regarding the Office 365 context, the trust between Azure AD and AD FS is unchanged, and not an OAuth 2.0 trust, so the thinking you see here should still apply to the token lifetimes involved at AD FS/WAP. So any time Azure AD decides you need to authenticate with AD FS again this stuff comes in to play. The Azure AD token lifetime documentation is a bit scattered, and not especially clear about how it changes when you’re a federated user. My current cobbled together understanding is that the Refresh Token lasts for 14 days and can be automatically refreshed again for a maximum lifetime of 90 days, but I believe the automatic refresh after 14 days doesn’t happen for federated users, so this is when you should see the redirection to AD FS. Having said that, there are a lot of things that are glossed over in this description, like use of KMSI, whether MFA is involved, whether MFA is passed as a Claim, whether Remember MFA is selected if using Azure AD, etc. For instance, if you select KMSI and crank Remember MFA up to 60 days, this could look a lot different than if you block both KMSI and Remember MFA.

    Appreciate this is further mud in the water, but hope it helps.

  16. Great article Tristan thanks for sharing. I was recently looking into “improving user experience” for an application that wasn’t handling refreshing the token correctly. Your article enabled me to understand what was happening and feedback to the application vendor.

  17. Hi. I’m having a similar timeout issue with a non-claims aware web app. i Installed this fix and can now set the PersistentAccessCookieExpirationTimeSec to 36000 seconds (10h) but the session exires after 1. I can see in chrome cookie manager that the cookie is set to 1 hour.
    The InactiveTransactionsTimeoutSec was very useful in my case because we are using SharePoint with reporting services and we noticed that the fetching reports timesout after 5mn. I checked this setting and it is set to 5 times by default. I changed it to 1 hour and the reports started working fine.
    But I’m still stuck with the 1 hour session timeout. you cannot set anything on the web app in ADFS since the this is a non-claimsawarerelyingpartytrust so no tokenliftime. if you guys have any idea about how to set the edge cookie to more than 1 hour that would be great. by the way I can decrease to less than 1 hour but cannot go beyond one hour.

  18. Hi Joe, both Web SSO token and WAP token will override the value of PersistentAccessCookieExpirationTimeSec if they are smaller. You will need to give both a higher value than the persisten cookie to give the edge cookie the same duration.

    It seems the edge access cookie will get the smallest value of either Web SSO or the WAP token.

  19. Tristan, What about forceful terminations? Is there a method for revoking the cert of a workplace joined machine in the case that a user’s account is disabled? We want to avoid the scenario of a terminated remote user whom can still maintain access until their immutable claim expires.

  20. Hi Mike. You shouldn’t need to revoke the cert per se, as AD FS should enforce revocation for disabled accounts. I don’t believe the workplace joined persistence changes anything here. However, you need to put this all in the context of the other token lifetimes in the chain, per my table. The Relying Party’s token lifetime might still be valid, for instance.

  21. This is an awesome article! I hope I see more from you around both OAuth 2 and Modern Auth 🙂

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.