Auth0 Home Blog Docs

Best practice Delegation Token Expiration handling MVC ASP.Net

token
delegation
mvc
access-token
tokens

#1

I have modified the NuGet package provided LoginCallback.ashx with added retrieval of an API Delegation Token. I would like to update the delegation token if it has expired in both the current request and cookie/session for future requests. Is there any best practices or configurations I can use to “hook” this in so that a delegation token refreshes/renews itself automatically?

I would be extending the HttpClient and in that do above things, however, just checking if there’s anything I can do with the SDK or configurations since the cookie is set with this cookie handler/encryptor/method in LoginCallback.ashx;

FederatedAuthentication.SessionAuthenticationModule.CreateSessionCookie(user);

Do I have to rebuild the cookie and set it with the same line of code or is there a better way? Have you built a wrapper to alleviate this functionality? Can it be done entirely in auth0 backend without having to touch this?

What we’re seeing is that the regular session token seems to get autorefreshed, but since the API delegation token isn’t refreshed as the refresh doesnt trigger or have a handler (if there even is a possibility of such) in the SDK so that it also gets a new delegation token. The delegation token has expired and the user sees nothing in the webapp because the api-token has expired.


#2

I’m assuming you’re referring to this library. When using the default approach based on the SessionAuthenticationModule you could try the following approach in order to customize the contents of the session with a token that requires renewal from time to time:

  1. In the login request handled by LoginCallback.ashx perform your additional logic to obtain the additional token.
  2. Include the token in the user object by adding a new key/value pair, for example, new KeyValuePair<string, object>("dlg_token", "[token]").

Given you added the delegation token before calling the CreateSessionCookie method the delegation token will be persisted to the cookie and available to subsequent requests. However, there will be no automatic renewal so when it expires the application will start to use an invalid token.

In order to handle the renewal of the token you can then do the following:

  1. Add an event handler to FederatedAuthentication.SessionAuthenticationModule.SessionSecurityTokenReceived; the event handler will be called for every request received that includes a session token.

  2. Within the handler implement logic that verifies if the delegation token needs to be renewed.

  3. If the token needs renewal, obtain the new token, update the existing token in the session token principal and request the cookie to be re-issued. Something along the lines of:

    void HandleSessionTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs e)
    {
        // check if you really need to refresh; don't reissue the cookie at every request
        var identity = (ClaimsIdentity)e.SessionToken.ClaimsPrincipal.Identity;
    
        identity.RemoveClaim(identity.FindFirst("dlg_token"));
        identity.AddClaim(new Claim("dlg_token", "[new_token]"));
    
        e.ReissueCookie = true;
    }
    

The previous approach should guarantee that the contents of the session token get updated with refreshed tokens as needed.


#3

Unfortunately, the SessionSecurityTokenReceived event isn’t raised when the delegation token has expired and the regular session token has not. That event isn’t triggered on every page load/OnAuthorizationRequest. I think I will have to add/extend the existing OnAuthorization handler to do the reissuance, not sure how to access to cookie and make it reissue itself since the event object isn’t there for reference though…


#4

From the docs one of the use cases for the event is to implement sliding sessions so it should be raised at every request processed by the managed module independently of the expiration of the session. There are other configurations that affect for which requests a managed module executes so you may want to check if the issue is not due to that. I did a few tests with ASP .NET MVC and the event was raised every time I triggered a controller action.


#5

I registered the handler in global.asax.cs and it never got called, when i added the handler in logincallback.ashx.cs it got called, but only if the session is created during that time. A resumed session based only off the cookie never registers itself with the handler.

So it seems to be dependent on where I register the handler. Now the question is where to register it so that it also handles the resumed sessions.


#6

So finding the appropriate location to bind to that event was a bit tricky. Not only because the event in global.asax.cs never fired, but it sort of only lived while the logincallback.ashx was called and thus bound that way.

So the solution? Well there are many blogs and articles that says the same thing, just use the FAM/SAM naming convention for events in global.asax.cs and it should solve itself, however, they all sort of have different information regarding the required web.config configuration for the event to even get raised.

Finding this article, I noticed yet another configuration that I had not yet tested;

https://docs.microsoft.com/en-us/dotnet/api/system.identitymodel.services.sessionauthenticationmodule?view=netframework-4.7

<configuration>  
  <system.webServer>  
    <modules>  
      <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>  
</modules>  
  </system.webServer>  
</configuration>  

This was the only variation that actually worked. Some mentions just modules in system.web httpModules and other variations, but they don’t work. Above configuration was the missing piece to get my protected void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs e) in global.asax.cs get called.


#7

The missing piece was a configuration line in web.config to get the event raised globally so I could register the eventhandler in global.asax.cs


#8