Based on recent testing SIF (sign-in-frequency) enforcement can be bypassed when refresh token is available for exchange¹ on third party² Web API clients.
I believe this to be undocumented by-design limitation of Azure AD Conditional Access and should be evaluated critically when using LOB (line-of-business) apps that can be considered your own/3rd party client apps.
What is the risk ?
– Any 3rd party azure AD OAuth2 web app (not spa) that relies on refresh tokens lifetime to align to restrictions configured in Sign-in-Frequency. If the back-end is evaluating the user session based on refresh token validity, then the session length can exceed that of which is configured in SIF.
¹ – Some clients require client_secret when exchanging refresh tokens, such clients typically live in the back-end
– It is worth mentioning, that even these clients, if they have proprietary endpoint to refresh refresh_tokens, can be abused if client is able to call the endpoint with any other session persistence mechanism that decouples the client from Authorization_code flow
² Third party clients mean non-Microsoft maintained OAuth2 applications.
- First party clients are MS native apps, that are registered already in the tenant, such as Azure CLI etc.
I am looking for peer review for this article – At this point I have confirmed these settings in one test environment, and would gladly accept information, which points out an misconfiguration (or misunderstanding) on my side.
I am also making this article public, because this is public information already (Github and MS forums), but I did not find a blog or docs article detailing these findings.
Scope
Testing setup
- 3rd party / custom Azure AD App – Web App (WEB API exchanges the Refresh Token)
- Redirect URI is type ’Web’
- 3rd party / custom Azure AD App – SPA web app (Client exchanges the Refresh Token)
- Redirect URI in is type ’Single-page application’
- 1st party app – Azure CLI
In my tests I request new access tokens with the refresh_token issued after authorization code flow. I will then try to use these refresh tokens in 1rd and 3rd party client, to see if refresh token is revoked after sign-in frequency time elapses
- I’ve also admin consented the API permissions to avoid triggering authorization_code flow (which we know works correctly)
Grant types
✅ – Sign-in-frequency is enforced
❌ – Sign-in-frequency is not enforced
clientType | refresh_token | authorization_code flow |
---|---|---|
first party client | ✅ | ✅ |
third party client (Web as platform configured in app) | ❌ | ✅ |
third party client (SPA as platform configured in app) | ✅ | ✅ |
Scopes types tested on 3rd party clients
These are tests on 3rd party client, done after the authorization code flow correctly prompts for reauthentication. (This is the point where I know, also refresh_tokens should not work)
- At this point I will only use refresh_token to bypass SIF enforcement
Graph mail.read

Custom API https://api-1313.m.dewi.red/user_impersonation

SPA Clients
Single page app correctly revoke also refresh tokens

Out-of-scope
This article does not explore similar ramifications when the use case includes PRT (Primary Refresh Token)
Flow descriptions
https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
When bypassing is possible
- User has access to refresh_token (Any library that stores the refresh_token on client side), or any implementation, where there is endpoint stores refresh-tokens, and issues those to clients with decoupled session management from Azure AD (User is not redirected to Azure AD for authorization_code)
results on Azure CLI
- Policy enforcement works

results on 3rd party client (Redirect URI type:web)
- Policy enforcement does not work

Log results show that enforcement would work, but reality is that this only applies to authorization code flow

Configured policies
Baseline
- MFA is required except for trusted locations

Session Policy

References
This behavior is already publicly documented

There are examples where adjusting to ”all apps” should’ve worked, but I suspect the case is on Single-Page-App type redirect URI, which I’ve also confirmed to work.
- As you can see, in my case I am already using all apps policy for SIF (Sign-in-Frequency)
AzureAD/microsoft-authentication-library-for-js#3156

End of blog
0 comments on “Bypassing sign-in frequency requirements for Conditional Access on 3rd party clients”