Refresh token flow in ASP.NET Core MVC environment
Confirm you've already contributed to this project or that you sponsor it
- [X] I confirm I'm a sponsor or a contributor
Version
3.x
Question
Hi, Kévin!
-
Could you provide some sample(-s) where refreshing tokens is implemented for MVC with cookie authentication scheme? If not, could you give us some ideas how it could be implemented? I found this one, but it looks so tricky that I can't believe this couldn't be reached in a more simple and native way.
-
Current behavior of a silent re-authentication not fully transparent for me. How does it happen? I see, that if the cookie expires re-authentication is triggered, goes silently (prompt=none?) and lands me on the main page with no respect to the page I came from. Is that alternate to refresh token flow? If so, can we configure it to use some
return_urlfor a seamless UX?
Hey,
Could you provide some sample(-s) where refreshing tokens is implemented for MVC with cookie authentication scheme? If not, could you give us some ideas how it could be implemented? I found this one, but it looks so tricky that I can't believe this couldn't be reached in a more simple and native way.
Unfortunately, I don't have a public sample for this scenario, but:
- There's nothing built-in in ASP.NET Core to handle token management so it's necessarily something you have to implement yourself.
- The link you shared is indeed one way to implement it (i.e using the events model of the cookie handler to refresh the tokens contained in the cookies when it's about to expire).
- If you don't like the previous approach and use
IHttpClientFactory, you can use a customDelegatedHandlerthat will do the same "is it expired?" check and renew the token prior to sending a HTTP client. Libraries like https://github.com/DuendeSoftware/Duende.AccessTokenManagement/blob/main/samples/Web/Startup.cs can simplify that for you (this one will store the updated tokens in the authentication cookie but you can customize that using your own implementation if you prefer).
Current behavior of a silent re-authentication not fully transparent for me. How does it happen? I see, that if the cookie expires re-authentication is triggered, goes silently (prompt=none?) and lands me on the main page with no respect to the page I came from. Is that alternate to refresh token flow? If so, can we configure it to use some return_url for a seamless UX?
Forget prompt=none for silent re-authentication: it used to work great but it's been killed by browser vendors (mostly Apple) when they started banning third-party cookies interactions: sending prompt=none silent authentication requests from iframes simply no longer works. Refresh tokens is pretty much the only viable approach these days.
Big thanks for advertising your competitors! :grin: I've taken a brief and realized there are no nuget packages released, what a weird thing...
About silent re-authentication, sorry, I didn't get - is it implemented in MS OIDC client and switched on by default? The fact is that it works, but I am unable to understand which part is responsible and where can we configure the process.
Big thanks for advertising your competitors! 😁 I've taken a brief and realized there are no nuget packages released, what a weird thing...
🤣 You can find the package on NuGet.org: https://www.nuget.org/packages/Duende.AccessTokenManagement
About silent re-authentication, sorry, I didn't get - is it implemented in MS OIDC client and switched on by default?
What we name "silent re-authentication" is just a regular authorization request with prompt=none sent from an iframe, which is not something the server-side MSFT OIDC handler does (which makes sense). A server-side component like the MSFT OIDC handler can definitely create a prompt=none request, but it's not going to be sent in an iframe, so you'll see a visible 302 redirection in the browser.
Okay, could you hint that to me, how can I configure ReturnUrl for silent authentication? I still don't understand the mechanism how it is implemented and where to dig. It just somehow works.
Okay, could you hint that to me, how can I configure ReturnUrl for silent authentication? I still don't understand the mechanism how it is implemented and where to dig. It just somehow works.
@kevinchalet could you help us on this, or should I open another issue?
Okay, could you hint that to me, how can I configure ReturnUrl for silent authentication? I still don't understand the mechanism how it is implemented and where to dig. It just somehow works.
As I already said, silent authentication via prompt=none is likely not what you want for an ASP.NET Core MVC client: the redirection would be visible by the user - aka the "flashing window" syndrome - and it's not a great user experience.
That said, creating prompt=none requests is not hard, if you're 100% sure that's what you want:
- With the new OpenIddict client:
var properties = new AuthenticationProperties
{
Parameters =
{
[Parameters.Prompt] = Prompts.None
}
};
return Challenge(properties, OpenIddictClientAspNetCoreDefaults.AuthenticationScheme);
- With the MSFT OIDC client:
var properties = new AuthenticationProperties
{
Parameters =
{
[OpenIdConnectParameterNames.Prompt] = "none"
}
};
return Challenge(properties, OpenIdConnectDefaults.AuthenticationScheme);
ought this fix the incorrect redirection after refreshing?
I have sadly no idea what "incorrect redirection" you're referring to.
2. Current behavior of a silent re-authentication not fully transparent for me. How does it happen? I see, that if the cookie expires re-authentication is triggered, goes silently (prompt=none?) and lands me on the main page with no respect to the page I came from. Is that alternate to refresh token flow? If so, can we configure it to use some
return_urlfor a seamless UX?
I'm talking about this part. I did nothing to implement silent re-authentication, so I have no idea what have I to check and where. You're my only hope :)
In other words, imagine the next situation - I explore web page A for ages so that my cookie expires, then I go to page B, and while the process is going the silent re-authentication happens, and then I expect to get to the page B, but it gets me to page HOME.
Silent authentication/prompt=none is not magic: it's just a regular authorization request. And with any authorization request, if the cookie still exists at the authorization server level, the provider doesn't need to re-authenticate the user and the authorization response can be directly returned without showing a login form. That's likely what you're seeing.
The only difference when using prompt=none is that the authorization server has to return an error if the user is not logged in or the client application hasn't been previously allowed by the user to access his resources: you CAN'T redirect the user to a login page when using prompt=none.
In other words, imagine the next situation - I explore web page A for ages so that my cookie expires, then I go to page B, and while the process is going the silent re-authentication happens, and then I expect to get to the page B, but it gets me to page HOME.
Hah, that's a clearer question 😄
When you're hitting an "authenticated-only" page while being unauthenticated, two things can happen:
- The MSFT OIDC handler is the
DefaultChallengeScheme: in this case, the OIDC handler automatically stores the current URL in thestateand will eventually return the user agent to that URL once the login process is done. - The cookie handler is the
DefaultChallengeScheme: in this case, the cookie handler stores the current URL in areturnUrlparameter and redirects the user agent to the local login page configured in the cookie options. If you want to redirect the user to the authorization server, you must make sureAuthenticationProperties.ReturnUrlis set to the correct value. Once set, the same logic as in the previous case applies.
If it still doesn't work, you'll have to share a repro.
Huh, big thanks and sorry for giving so out of square description ) I'll check this right now/
Big thanks again, the issue fixed!
Great to hear!