Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practice for persisting tokens using Client Credentials flow

I have an ASP.NET Core MVC application allowing anonymous users. This app is calling an ASP.NET Web API that is protected by Identity Server 4. I have created a client in Identity Server describing the MVC app (client) and given it access to the api scope like this:

new Client
{
    ClientId = "my-mvc-client-app",
    AllowedGrantTypes = GrantTypes.ClientCredentials,

    RequireConsent = false,
    ClientSecrets = new List<Secret> { new Secret("this-is-my-secret".Sha256()) },
    AllowedScopes = new List<string>
    {
        StandardScopes.OpenId.Name,
        StandardScopes.Profile.Name,
        StandardScopes.OfflineAccess.Name,
        "my-protected-api"
    },
    RedirectUris = new List<string>
    {
        "http://localhost:5009/signin-oidc",
    }
}

In my MVC app, I'm using TokenClient to get a token that I can use when making requests to the protected API like this:

var disco = await DiscoveryClient.GetAsync("http://localhost:5010");
var tokenClient = new TokenClient(disco.TokenEndpoint, clientId, clientSecret);
var tokenResponse = await tokenClient.RequestClientCredentialsAsync("hrmts-test-candidate-api-scope");

This works fine, but I'm requesting new tokens from Identity Server on every request, which is probably not a good idea.

What is the best practice for handling the tokens? How can I persist them on the client (the MVC app) and how can I handle refresh tokens to make sure the client gets a new token when necessary?

like image 305
henningst Avatar asked Sep 26 '16 12:09

henningst


People also ask

What credentials can the OAuth 2.0 client credentials grant flow use?

The OAuth 2.0 client credentials grant flow permits a web service (confidential client) to use its own credentials, instead of impersonating a user, to authenticate when calling another web service.

Why does the client credentials grant type not use refresh tokens?

The token endpoint does not issue a refresh token as refresh tokens are not supported by the client credentials grant. The client credentials grant type is less secure than the authorization code grant type.

How do you test client credentials flow?

How it works. The application authenticates with the Auth0 Authorization Server using its Client ID and Client Secret ( /oauth/token endpoint). Auth0 Authorization Server validates the Client ID and Client Secret. Auth0 Authorization Server responds with an access token.


1 Answers

You need to wrap that client in a managed service of some kind (as a singleton) so that you can use it anywhere you need. We have a token component that we use for server to server communication that follows this flow:

public class ServerTokenComponent
{
    private TokenResponse Token { get; set; }
    private DateTime ExpiryTime { get; set; }
    public async Task<TokenResponse> GetToken()
    {
        //use token if it exists and is still fresh
        if (Token != null && ExpiryTime > DateTime.UtcNow)
        {    
            return Token;
        }     

        //else get a new token
        var client = new TokenClient("myidpauthority.com","theclientId","thesecret")
        var scopes = "for bar baz";

        var tokenResponse = await client.RequestClientCredentialsAsync(scopes);

        if (tokenResponse.IsError || tokenResponse.IsHttpError)
        {
            throw new SecurityTokenException("Could not retrieve token.");
        }

        //set Token to the new token and set the expiry time to the new expiry time
        Token = tokenResponse;
        ExpiryTime = DateTime.UtcNow.AddSeconds(Token.ExpiresIn);

        //return fresh token
        return Token;
    }
}
like image 142
Lutando Avatar answered Oct 12 '22 15:10

Lutando