SteppingRazor
SteppingRazor

Reputation: 1272

ADAL native application token expires after 12 hours

I've created the .net console application which is the client of my web api. Both apps are registered in azure. I want my console app to run without user interaction. Console app checks the message queue and if the message arrives, it does some calculation and sends back the data to my web api. I use adal to authenticate my connection. I authenticate by secret key. Since my client uses generated code by AutoRest I added DelegatingHandler to catch every request and add the authorization header before i send it:

public class ClientHandler : DelegatingHandler
{
    protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        AuthenticationContext authContext = Constants.authContext;
        ClientCredential clientCredential = Constants.clientCredential;
        string apiId = Constants.apiId;
        string tokenType = Constants.tokenType;

        // ADAL includes token in memory cache, so this call will only send a message to the server if the cached token is expired.
        var result = await authContext.AcquireTokenAsync(apiId, clientCredential);
        request.Headers.Authorization = new AuthenticationHeaderValue(tokenType, result.AccessToken);

        return await base.SendAsync(request, cancellationToken);
    }
}

As you can see I am using already defined authorization context. Thanks to code above I can get the token without user interaction. And this work just fine! However after 12 hours the application starts returning Unauthorized error. The question is how do I prevent it? I thought that AcquireToken method takes care of the token expiration. Am I missing something?

EDIT: Constant class:

public static class Constants
{
    public static string aadInstance = ConfigurationManager.AppSettings["aadInstance"];
    public static string tenant = ConfigurationManager.AppSettings["aadTenantName"];
    // this application id
    public static string clientId = ConfigurationManager.AppSettings["clientApi:ClientId"];
    // the key which it can be authenticated
    public static string appKey = ConfigurationManager.AppSettings["clientApi:AppKey"];
    // the id of the api
    public static string apiId = ConfigurationManager.AppSettings["apiId"];
    public static string authority = String.Format(CultureInfo.InvariantCulture, aadInstance, tenant);
    public static string tokenType = ConfigurationManager.AppSettings["TokenType"];
    public static AuthenticationContext authContext = null;
    public static ClientCredential clientCredential = null;

    public static async Task<TokenCredentials> Authenticate()
    {
        authContext = new AuthenticationContext(authority);
        clientCredential = new ClientCredential(clientId, appKey);
        var result = await authContext.AcquireTokenAsync(apiId, clientCredential);
        return new TokenCredentials(result.AccessToken, tokenType);
    }
}

Upvotes: 0

Views: 1121

Answers (2)

cuongle
cuongle

Reputation: 75326

You can change the code to create AuthenticationContext everytime and noneed to keep it as static on Constants class

Upvotes: 1

Tom Sun
Tom Sun

Reputation: 24569

The question is how do I prevent it?

According to official document, Access Token Lifetime is between 10 minutes to 1 day. So we can extend the Access token lifetime up to 1 days, but we can't prevent it expiration. We also can get the way how to Configurable Token Lifetimes in Azure Active Directory from the document.

A malicious actor that has obtained an access token can use it for extent of its lifetime. Adjusting access token lifetime is a trade-off between improving system performance and increasing the amount of time that the client retains access after the user’s account is disabled.

We can use refresh token to otain new access/fresh token when the current access token expires. And the refresh token default expiration 14 days. So we no need to call all the azure server with every request. We also can get according ExpiresOn when we get the access token. If the access token is not expired then we no need to get the access token.

var result = await authContext.AcquireTokenAsync(apiId, clientCredential);

enter image description here

Upvotes: 0

Related Questions