title: Getting a new refresh token with AD FS 4.0 (2016) or higher
body: <p>I configured AD FS 2016 to support authentication of a &quot;Native Application&quot; via OAuth2/OpenID Connect using Authorization Code Grant with PKCE. I created a relying party and configured (for testing purposes) token lifetimes by setting the following:</p>
  <pre><code>Set-AdfsRelyingPartyTrust -TargetName MyRPT -IssueOAuthRefreshTokensTo AllDevices -TokenLifetime 3
  
  Grant-AdfsApplicationPermission -ClientRoleIdentifier MyClient -ServerRoleIdentifier MyRPT -ScopeNames openid,profile,email
  
  Set-AdfsProperty -SSOLifetime 7 -PersistenSsoEnabled $false
  </code></pre>
  <p>...and that gives me Access/ID Tokens that expire after 3 minute and Refresh Tokens that expire after 7 (actually 14, see below) minutes. I also disabled Persistent SSO, so I get no session cookie. All good.</p>
  <p>After a successful authentication, my client issues a POST request to the /oauth2/token endpoint, passing the following parameters:</p>
  <ul>
  <li>client_id: &quot;MyClient&quot;</li>
  <li>code: ...</li>
  <li>redirect_uri: ...</li>
  <li>code_verifier: ...</li>
  <li>grant_type: &quot;authorization_code&quot;</li>
  </ul>
  <p>I get a valid response with the following:</p>
  <pre><code>{
    &quot;access_token&quot;: &quot;...&quot;,
    &quot;token_type&quot;: &quot;bearer&quot;,
    &quot;expires_in&quot;: 180,
    &quot;resource&quot;: &quot;MyRPT&quot;,
    &quot;refresh_token&quot;: &quot;...&quot;,
    &quot;refresh_token_expires_in&quot;: 419,
    &quot;scope&quot;: &quot;email profile openid&quot;,
    &quot;id_token&quot;: &quot;...&quot;
  }
  </code></pre>
  <p>Awesome.</p>
  <p>Then about 10 seconds before the access token is due to expire, the client issues another POST request to /oauth2/token, this time with the following parameters:</p>
  <ul>
  <li>refresh_token: ...</li>
  <li>grant_type: &quot;refresh_token&quot;</li>
  <li>client_id: &quot;MyClient&quot;</li>
  </ul>
  <p>And the following successful response is returned:</p>
  <pre><code>{
    &quot;access_token&quot;: &quot;...&quot;,
    &quot;token_type&quot;: &quot;bearer&quot;,
    &quot;expires_in&quot;: 180,
    &quot;id_token&quot;: &quot;...&quot;
  }
  </code></pre>
  <p>Note that this time no refresh token is returned. The same happens another FOUR times (about 14 mins in total, so <em>twice</em> the SSOLifetime then?) while the refresh token is still valid, and then finally, at the fourth request for a new access token I get a 400 error with the following body:</p>
  <pre><code>{
    &quot;error&quot;:&quot;invalid_grant&quot;,
    &quot;error_description&quot;:&quot;MSIS9615: The refresh token received in \u0027refresh_token\u0027 parameter has expired.&quot;
  }
  </code></pre>
  <p><a href="https://i.stack.imgur.com/2uWun.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/2uWun.png" alt="Token refresh requests" /></a></p>
  <p>Which kinda makes sense, but... shouldn't a new refresh token be issued when the current refresh token is close to the expiration time?</p>
  <p>The <a href="https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/overview/ad-fs-openid-connect-oauth-flows-scenarios#authorization-code-grant-flow" rel="nofollow noreferrer">Official Docs</a> are somewhat cryptic on the matter:</p>
  <blockquote>
  <p>Although refresh tokens aren't revoked when used to acquire new
  access tokens, you are expected to discard the old refresh token. As
  per the OAuth 2.0 spec says: &quot;The authorization server MAY issue a new
  refresh token, in which case the client MUST discard the old refresh
  token and replace it with the new refresh token. The authorization
  server MAY revoke the old refresh token after issuing a new refresh
  token to the client.&quot; <strong>AD FS issues refresh token when the new refresh
  token lifetime is longer than previous refresh token lifetime</strong>. To view
  additional information on AD FS refresh token lifetimes, visit AD FS
  Single Sign On Settings.</p>
  </blockquote>
  <p>Err, what? Let me write that in pseudo code:</p>
  <pre><code>if (newRefreshTokenLifetime &gt; previousRefreshTokenLifetime) {
    issueNewRefreshToken();
  }
  </code></pre>
  <p>...but that would be <em>always</em> then, wouldn't it?</p>
  <p>Any idea on how to configure AD FS so that it issues new refresh tokens as well when needed? Ideally it would be nice to have <a href="https://auth0.com/docs/security/tokens/refresh-tokens/refresh-token-rotation" rel="nofollow noreferrer">refresh token rotation</a>, but one thing at a time...</p>