16

I am trying to set a token expiration time dynamically, but it appears it just keeps defaulting to 20 minutes.

Here is my ConfigureAuth:

public void ConfigureAuth(IAppBuilder app)
{

        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider(""),
            // In production mode set AllowInsecureHttp = false
            AllowInsecureHttp = true
        };

        // Enable the application to use bearer tokens to authenticate users
        app.UseOAuthBearerTokens(OAuthOptions);

}

Here is my GrantResourceOwnerCredentials method:

    public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {

        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

        var hasValidLogin = (new login().authenticate(context.UserName, context.Password, "") == "valid");

        if (hasValidLogin == false)
        {
            context.SetError("invalid_grant", "The user name or password is incorrect.");
            return Task.FromResult<object>(null);
        }

        var oAuthIdentity = CreateIdentity(context);
        var oAuthProperties = CreateProperties(context);

        AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, oAuthProperties);

        context.Validated(ticket);
        return Task.FromResult<object>(null);
    }

And here is my SetProperties method where I can setting the expiration:

    public static AuthenticationProperties CreateProperties(OAuthGrantResourceOwnerCredentialsContext context)
    {

        IDictionary<string, string> data = new Dictionary<string, string>
        {
            { "client_id", context.ClientId }
        };

        var response = new AuthenticationProperties(data);
        response.ExpiresUtc = DateTime.Now.AddMonths(1);

        return response;
    }

Even after that, the token is returning:

{
  "access_token": ".....",
  "token_type": "bearer",
  "expires_in": 1199,
  "client_id": ".....",
  ".expires": "Fri, 13 Nov 2015 20:24:06 GMT",
  ".issued": "Fri, 13 Nov 2015 20:04:06 GMT"
}

Any ideas why I cannot set the expiration where I currently am? This server will take a variety of different clients with different specified expiration times, therefore I figured this is the place to do this. Is there somewhere else that I should doing this at? Thanks!

user3726393
  • 265
  • 1
  • 2
  • 11

4 Answers4

18

We have a similar situation, with different clients that have different token timeouts so we wanted to be able to set the expiration accordingly. In the AuthenticationTokenProvider we implemented we were setting the expiration but it was being overwritten by the time the token was being signed.

The solution we ended up happy with was overriding the TokenEndpoint method. We're then able to implement a client specific expiration :

    public override Task TokenEndpoint(OAuthTokenEndpointContext context)
    {
        if (context.TokenIssued)
        {
            // client information
            var accessExpiration = DateTimeOffset.Now.AddSeconds(accessTokenTimeoutSeconds);
            context.Properties.ExpiresUtc = accessExpiration;
        }

        return Task.FromResult<object>(null);
    }

*Edited to resolve a race condition.

Michael
  • 1,028
  • 18
  • 25
  • 3
    I don't think this is safe. `context.Options` is shared among requests. You'll be overwriting `AccessTokenExpireTimeSpan` for requests going in parallel. – user3608068 Jun 29 '17 at 13:00
  • 1
    Thank you @user3608068, I have updated the answer accordingly! – Michael Jun 29 '17 at 16:48
  • 1
    Thanks for sharing, I am also currently configuring an API to issue tokens with varying expiration times based on the client. This works perfectly. – mfcallahan Aug 14 '17 at 20:53
11

The behavior you're seeing is directly caused by the fact the OAuth2 authorization server always discards your own expiration when you set it in the GrantResourceOwnerCredentials notification (the other Grant* notifications are also impacted): https://github.com/jchannon/katanaproject/blob/master/src/Microsoft.Owin.Security.OAuth/OAuthAuthorizationServerHandler.cs#L386

A work around is to set the expiration date in AuthenticationTokenProvider.CreateAsync (the class you use for OAuthAuthorizationServerOptions.AccessTokenProvider):

Simply set context.Ticket.Properties.ExpiresUtc with the expiration date of your choice, and it should work as intented:

public class AccessTokenProvider : AuthenticationTokenProvider
{
    public override void Create(AuthenticationTokenCreateContext context)
    {
        context.Ticket.Properties.ExpiresUtc = // set the appropriate expiration date.

        context.SetToken(context.SerializeTicket());
    }
}

You can also take a look at AspNet.Security.OpenIdConnect.Server, a fork of the OAuth2 authorization server offered by OWIN/Katana that natively supports setting the expiration date from GrantResourceOwnerCredentials: https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/tree/dev

Kévin Chalet
  • 39,509
  • 7
  • 121
  • 131
  • @Pinpoint But why "OAuth2 authorization server always discards your own expiration when you set it in the GrantResourceOwnerCredentials" ? – George Botros Dec 27 '15 at 12:51
  • Probably a bug (it wouldn't be the first one, and since this component is no longer maintained, there's no fix) – Kévin Chalet Dec 27 '15 at 12:59
  • @Pinpoint I have the same behavior with https://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.OAuth/Provider/OAuthAuthorizationServerProvider.cs – George Botros Dec 27 '15 at 13:35
  • It's the same project (I just use GitHub because it's easier to target specific lines) – Kévin Chalet Dec 27 '15 at 13:38
  • @Pinpoint I was replaying to "this component is no longer maintained", I think it is – George Botros Dec 27 '15 at 14:03
  • Nope, it's not, I'm afraid: https://katanaproject.codeplex.com/SourceControl/list/changesets. MSFT is fully focusing on vNext (btw, the OAuth2 authorization server won't be ported to ASP.NET 5: http://stackoverflow.com/a/29144031/542757) – Kévin Chalet Dec 27 '15 at 14:08
3

I'll throw this out here, as of right now, there is simpler way without creating a new class, it's just setting options:

OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
    ...
    AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
    ..
};
Erti-Chris Eelmaa
  • 25,338
  • 6
  • 61
  • 78
  • 1
    Erti-Chris Eelmaa, this way you set a general timeout for all tokens. The question is for setting it dynamically. – jumuro Apr 22 '16 at 08:48
2

You can set it in the TokenEndPoint method instead of GrantResourceOwnerCredentials method. Please see my answer to a similar question here.

I hope it helps.

Community
  • 1
  • 1
jumuro
  • 1,517
  • 15
  • 17