Configure Microsoft Entra Token Lifetime Policies

September 10, 2026

Microsoft Entra token lifetime policies let administrators control the lifetime of access, ID, and SAML tokens issued by the Microsoft identity platform. They suit applications with a defined security or performance requirement. They are not a replacement for Conditional Access session controls.

TL;DR: Token lifetime policies are managed only through Microsoft Graph PowerShell or the Graph API (there is no admin center UI), they only change access, ID, and SAML token lifetimes, and an organization-level policy overrides an application-level one. If you want to control how often users sign in, use Conditional Access sign-in frequency instead.

Do you need a policy at all? A common reason to lengthen a lifetime is so a script can run for more than an hour. Many Microsoft libraries and applications, including the Microsoft Graph PowerShell SDK, proactively refresh access tokens as needed, so you often do not have to change the policy. Confirm the problem exists before you change a default.

Which control do you need?

Requirement Use
Shorten or lengthen how long an access, ID, or SAML token is valid for one app Token lifetime policy (this guide)
Force users to re-authenticate every few hours or days Conditional Access sign-in frequency
Control persistent browser sessions or web session length Conditional Access session controls
Change refresh-token or session-token lifetimes Not possible. Retired January 30, 2021

Understand what the policy controls

Token lifetime policies apply to access tokens, ID tokens, and SAML tokens. Despite the property name AccessTokenLifetime, Microsoft Entra uses that one property for all three.

  • Access tokens authorize a client to call a protected resource or API.
  • ID tokens provide claims about an authenticated user to a web or native application. The default lifetime is one hour.
  • SAML tokens are commonly used by federated SaaS applications and WS-Federation services. The default lifetime is one hour. The NotOnOrAfter value is set to the policy lifetime plus a five-minute clock-skew allowance.
  • Refresh and session tokens are not configurable through token lifetime policies.

The default access-token lifetime is a random value between 60 and 90 minutes, about 75 minutes on average. When both the client and the resource support Continuous Access Evaluation (CAE), Microsoft Entra may extend the lifetime to 24–28 hours while keeping the ability to revoke access after critical events such as account disablement or a password change.

The configurable range is 10 minutes (00:10:00) to 23 hours, 59 minutes, 59 seconds (23:59:59), in hh:mm:ss format. A shorter lifetime limits how long a stolen token is useful but increases token-acquisition traffic. A longer lifetime reduces renewals but extends the window in which a stolen token works.

Limits and gotchas

  • No portal UI. Policies are managed only through Microsoft Graph or the Microsoft Graph PowerShell SDK, not the Microsoft Entra admin center.
  • Organization-level policy wins. If a policy is assigned at the organization level, it overrides any application-level policy. If your app policy seems to be ignored, check for an organization default first.
  • Personal Microsoft accounts are not supported for apps whose signInAudience includes personal accounts.
  • Managed identities are not supported.
  • SharePoint and OneDrive: the policy applies only to mobile and desktop clients, not web browser sessions. Use Conditional Access session controls for the browser.
  • Licensing: Microsoft’s current article does not list a licence requirement, but earlier versions referenced Microsoft Entra ID P1. Confirm against your tenant’s licensing before rollout.

Before you begin

Use a test application, and a non-production tenant where possible. Record the application or service-principal object ID, the token type, the required lifetime, and the rollback steps before you change anything.

Install the latest Microsoft Graph PowerShell SDK, then connect with an account that is permitted to manage app registrations and to consent to the Graph scopes below. Review the requested permissions before you grant consent.

Install-Module Microsoft.Graph -Scope CurrentUser

Connect-MgGraph -Scopes @(
    "Policy.ReadWrite.ApplicationConfiguration",
    "Policy.Read.All",
    "Application.ReadWrite.All"
)

Policies attach to the object ID, not the application (client) ID. Look up both:

# App registration (object ID = Id, client ID = AppId)
Get-MgApplication -Filter "displayName eq 'MyApp'" |
    Select-Object DisplayName, Id, AppId

# Service principal (enterprise application)
Get-MgServicePrincipal -Filter "displayName eq 'MyApp'" |
    Select-Object DisplayName, Id, AppId

Create a policy and assign it to an application

This example creates a policy that sets the access and ID token lifetime to four hours and assigns it to an app registration. Replace the placeholder with your application’s object ID.

# Create the policy (4 hours)
$policyParams = @{
    Definition = @(
        '{"TokenLifetimePolicy":{"Version":1,"AccessTokenLifetime":"04:00:00"}}'
    )
    DisplayName           = "WebPolicyScenario"
    IsOrganizationDefault = $false
}
$tokenLifetimePolicyId = (New-MgPolicyTokenLifetimePolicy -BodyParameter $policyParams).Id

# Assign it to the app registration
$applicationObjectId = "<application-object-id>"

$refParams = @{
    "@odata.id" = "https://graph.microsoft.com/v1.0/policies/tokenLifetimePolicies/$tokenLifetimePolicyId"
}
New-MgApplicationTokenLifetimePolicyByRef -ApplicationId $applicationObjectId -BodyParameter $refParams

Confirm the policy exists and is assigned:

Get-MgPolicyTokenLifetimePolicy -TokenLifetimePolicyId $tokenLifetimePolicyId
Get-MgApplicationTokenLifetimePolicy -ApplicationId $applicationObjectId

Create a policy and assign it to a service principal

A service principal is the tenant-level instance of an application. This example sets an eight-hour lifetime and assigns it through Microsoft Graph.

$spPolicyParams = @{
    Definition = @(
        '{"TokenLifetimePolicy":{"Version":1,"AccessTokenLifetime":"08:00:00"}}'
    )
    DisplayName           = "ContosoServicePrincipalPolicy"
    IsOrganizationDefault = $false
}
$spPolicyId = (New-MgPolicyTokenLifetimePolicy -BodyParameter $spPolicyParams).Id

$servicePrincipalObjectId = "<service-principal-object-id>"

# Single quotes keep $ref literal. In double quotes PowerShell would expand it to an empty variable.
$uri = 'https://graph.microsoft.com/v1.0/servicePrincipals/{0}/tokenLifetimePolicies/$ref' -f $servicePrincipalObjectId

$body = @{
    "@odata.id" = "https://graph.microsoft.com/v1.0/policies/tokenLifetimePolicies/$spPolicyId"
} | ConvertTo-Json

Invoke-MgGraphRequest -Method POST -Uri $uri -Body $body -ContentType "application/json"

List the policies assigned to the service principal:

Invoke-MgGraphRequest -Method GET `
    -Uri "https://graph.microsoft.com/v1.0/servicePrincipals/$servicePrincipalObjectId/tokenLifetimePolicies"

Verify the policy is working

Do not assume it took effect. Sign in to the app to get a new access token, decode the payload, and compare exp with iat. Use a test token only, and never paste real tokens into online decoders: access tokens are credentials.

$token   = "<paste-a-test-access-token>"
$payload = $token.Split('.')[1].Replace('-','+').Replace('_','/')
switch ($payload.Length % 4) { 2 { $payload += '==' } 3 { $payload += '=' } }

$claims = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($payload)) | ConvertFrom-Json
[TimeSpan]::FromSeconds($claims.exp - $claims.iat)   # should match the policy value

Test with your own application and API rather than the Microsoft Graph PowerShell SDK, which refreshes tokens proactively and can hide the effect of the policy. CAE-capable clients can also receive longer-lived tokens, so test with CAE behavior in mind. Also check silent renewal, API authorization, sign-out, and Conditional Access interactions before extending the change to production.

Optional: set an organization-wide default

Setting IsOrganizationDefault = $true applies the policy to every application in the tenant and overrides application-level policies. Use it only after testing, with change approval and a rollback plan.

Audit existing policies

This lists every token lifetime policy in the tenant, flags legacy ones that still contain retired refresh or session settings (MaxInactiveTime, MaxAgeSingleFactor, MaxAgeMultiFactor, and similar, which Microsoft no longer honors), and shows what each policy applies to.

Get-MgPolicyTokenLifetimePolicy | ForEach-Object {
    $applies = (Invoke-MgGraphRequest -Method GET `
        -Uri "https://graph.microsoft.com/v1.0/policies/tokenLifetimePolicies/$($_.Id)/appliesTo").value

    [pscustomobject]@{
        Name       = $_.DisplayName
        Id         = $_.Id
        OrgDefault = $_.IsOrganizationDefault
        Legacy     = (($_.Definition -join '') -match 'MaxInactiveTime|MaxAge')
        AppliesTo  = ($applies.displayName -join ', ')
    }
} | Format-Table -AutoSize

Review or remove legacy policies so nobody mistakes retired settings for active controls.

Roll back

Remove the assignment first, then delete the policy. Do this for each assignment and keep the policy ID from creation.

# Application
Remove-MgApplicationTokenLifetimePolicyByRef -ApplicationId $applicationObjectId `
    -TokenLifetimePolicyId $tokenLifetimePolicyId

# Service principal
$uri = 'https://graph.microsoft.com/v1.0/servicePrincipals/{0}/tokenLifetimePolicies/{1}/$ref' -f $servicePrincipalObjectId, $spPolicyId
Invoke-MgGraphRequest -Method DELETE -Uri $uri

# Delete the policies when they are no longer needed
Remove-MgPolicyTokenLifetimePolicy -TokenLifetimePolicyId $tokenLifetimePolicyId
Remove-MgPolicyTokenLifetimePolicy -TokenLifetimePolicyId $spPolicyId

Disconnect-MgGraph

Use Conditional Access when the goal is sign-in frequency

If the requirement is “make users sign in again every few hours or days,” a token lifetime policy is usually the wrong control. Configure Conditional Access sign-in frequency instead. It sets how long a user can stay signed in before Microsoft Entra prompts for authentication again, and it works with applications that use OAuth 2.0 or OpenID Connect. Conditional Access session controls also manage persistent browser sessions. Test with the apps, device states, authentication methods, and user groups in scope.

Security and testing checklist

  • Define the security or performance reason for changing the default before creating a policy.
  • Use the narrowest scope that meets the requirement: an application or service principal, not the organization.
  • Do not treat a longer token lifetime as a substitute for Conditional Access, CAE, strong authentication, or API authorization checks.
  • Test token renewal, sign-out, revocation, CAE behavior, and API validation in non-production first.
  • Monitor sign-in logs and application errors after rollout.
  • Document the policy owner, lifetime value, affected application, change date, and rollback steps.

Client applications should treat access tokens as opaque strings. The resource API must validate that an incoming token is intended for it and has a valid issuer, signature, audience, and expiry. Use Microsoft authentication libraries or Microsoft.Identity.Web instead of writing token validation yourself.

References

Topics:
Read next
October 23, 2026

Storm-0940 Used AI Agents Against 2,250+ Tenants via ConnectWise

Microsoft attributes a ConnectWise multi-tenant app compromise to Storm-0940 and says the actor used the open-source ARTEX AI framework to attempt sign-ins to 2,250+ tenants, sometimes reaching privileged access in under three hours.