2013-11-15

In the last post I showed how to add a simple username/password (aka resource owner password credentials flow) authorization server to Web API v2. This has several advantages:

The client does not need to hold on to the user credentials after the token has been requested (e.g. for re-submitting them on every request)

The user does not need to re-enter his credentials for the lifetime of the token

The back end does not need to validate the password on each request (passwords become harder and harder too secure – and validation becomes increasingly expensive)

Credential validation is factored out into the authorization server, and does not “pollute” the business services

This is already a big improvement. But there are also some security/architecture considerations:

Once the token has been issued, there is no “built-in” way to revoke it. Or in other words you’d need to write your own mechanism for that which often involves database checks on each request. Doable – but often defeats the purpose.

Related to that – when a claim that’s inside the token changes in your back end (e.g. role membership) you cannot easily “update” the token. You need to wait until the old token expires for the new claims to propagate. A good example of that is Windows authentication – when an admin adds or removes you from a Windows group, you need to logoff/logon for your Windows token to get updated.

For these reasons you need to find a balance between usability (how often must the user re-authenticate) and security/enforcing business requirements.

Refresh tokens can potentially improve the situation but also increase complexity. A refresh token is a long lived token that allows requesting new access tokens without having to present the user credentials again. This means that the access token itself could be short lived and whenever the refresh token is used to request a new access token, the contents of that access token can be updated. But with that power, you’ll have more responsibilities. Let’s have a look.

Refresh tokens must be bound to a client – you typically don’t want that a refresh token from your desktop client can be used from the web client and so on (this is also important for being able to revoke them). That means you need to introduce client authentication (or at least identification). This also means that your client needs an embedded credential (or must use dynamic client registration – but that is out of scope for this post). Depending on the client type this might not be a real secret and shouldn’t be used to base further security decisions on.

This changes how the ValidateClientAuthentication method looks like. We need to validate client credentials, and need to make the client ID available in the pipeline for later processing (unfortunately we need to use the OWIN context for that because of some shortcoming in the current middleware API).

public override async Task ValidateClientAuthentication
  (OAuthValidateClientAuthenticationContext context)

{

    // validate client credentials (demo)

    // should be stored securely (salted, hashed, iterated)

    string id, secret;

    if (context.TryGetBasicCredentials(out id, out secret))

    {

        if (secret == “secret”)

        {

            // need to make the client_id available for later security checks

            context.OwinContext.Set<string>(“as:client_id”, id);

            context.Validated();

        }

    }

}

We also need slight modifications to the GrantResourceOwnerCredentials method. In there we need to add some metadata to the resulting authentication ticket about the client. This will be used later when it comes to creating and persisting the refresh token.

public override async Task GrantResourceOwnerCredentials
  (OAuthGrantResourceOwnerCredentialsContext context)

{

    // validate user credentials (demo mode)

    // should be stored securely (salted, hashed, iterated)       

    if (context.UserName != context.Password)

    {

        context.Rejected();

        return;

    }

 

    // create identity

    var id = new ClaimsIdentity(“Embedded”);

    id.AddClaim(new Claim(“sub”, context.UserName));

    id.AddClaim(new Claim(“role”, “user”));

 

    // create metadata to pass on to refresh token provider

    var props = new AuthenticationProperties(new Dictionary<string, string>

        {

            { “as:client_id”, context.ClientId }

        });

 

    var ticket = new AuthenticationTicket(id, props);

    context.Validated(ticket);

}

At this point, the refresh token handler alongside the authentication ticket need to be persisted in some data store – – I’ll skip that for now and come back to it later.

There is one method you need to add to the authorization server provider. This method is called when the actual refresh token request comes in. In there you need to verify that the current client is actually the client that requested the token in the first place (the client binding). Here’s also your chance to modify the outgoing access token when you want to update claims etc..

public override async Task GrantRefreshToken(
  OAuthGrantRefreshTokenContext context)

{

    var originalClient = context.Ticket.Properties.Dictionary["as:client_id"];

    var currentClient = context.OwinContext.Get<string>(“as:client_id”);

 

    // enforce client binding of refresh token

    if (originalClient != currentClient)

    {

        context.Rejected();

        return;

    }

 

    // chance to change authentication ticket for refresh token requests

    var newId = new ClaimsIdentity(context.Ticket.Identity);

    newId.AddClaim(new Claim(“newClaim”, “refreshToken”));

 

    var newTicket = new AuthenticationTicket(newId, context.Ticket.Properties);

    context.Validated(newTicket);

}

The last missing piece is persistence – this is encapsulated in an IAuthenticationProvider derived class. Here you need to create a secure handle for the refresh token and associate the authentication ticket with it to store it in some data store. Refresh token handles should be treated as secrets and should be stored hashed (I leave that as an exercise). Another security decision to make is if you want the refresh handle to be one-time use only, or if you re-use the same handle for that client/application combination. Most implementations I have seen so far seem to re-use the handle, my sample uses the one-time approach:

// sample persistence of refresh tokens

// this is not production ready!

public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider

{

    private static ConcurrentDictionary<string, AuthenticationTicket> _refreshTokens = new ConcurrentDictionary<string,AuthenticationTicket>();

 

    public async Task CreateAsync(AuthenticationTokenCreateContext context)

    {

        var guid = Guid.NewGuid().ToString();

           

        // maybe only create a handle the first time, then re-use

        _refreshTokens.TryAdd(guid, context.Ticket);

 

        // consider storing only the hash of the handle

        context.SetToken(guid);

    }

 

    public async <span lang="EN-US" style="background-image:none;background-repeat:repeat

Show more