Slow beahaviour using BearerToken

Hi guys,
I’m having a strange behaviour using custom BearerToken authentication. To clarify, method “A” called using user password login execute in 65ms, while using BearerToken execute in 2 seconds. Any idea?

This is my app host


            var auth = new AuthFeature(() => new CustomAuthUserSession(),
                new IAuthProvider[]
                {
                    new PinAuthProvider(),
                    new UserNameAuthProvider(),
                    new AutomaticAuthProvider(),
                    new CustomApiKeyAuthProvider(appSettings){
                        RequireSecureConnection = false
                    }
                }
            );
            auth.AllowGetAuthenticateRequests = req => true;
            Plugins.Add(auth);

and my CustomApiKeyAuthProvider is this

public class CustomApiKeyAuthProvider : ApiKeyAuthProvider
    {
        public CustomApiKeyAuthProvider(IAppSettings appSettings) : base(appSettings)
        {
        }

        public override object Authenticate(IServiceBase authService, IAuthSession session, Authenticate request)
        {
            var repository = new ServiceRepository();
            var user = repository.UserDecriptedVerify(request.Password);
            if (user != null && user.DoExpiryDate > DateTime.Now)
            {
                var sessionBag = authService.GetSessionBag();
                sessionBag.Set(user);

                session.IsAuthenticated = true;

                return new AuthenticateResponse
                {
                    UserId = user.Id.ToString(),
                    UserName = user.UserCode,
                    SessionId = session.Id,
                    DisplayName = user.UserCode,
                    ResponseStatus = new ResponseStatus(),
                    BearerToken = request.Password,
                    Meta = new Dictionary<string, string>()
                    {
                        ["CultureCode"] = user.PreferredCultureCode
                    }
                };                
            }

            throw new AuthenticationException(ErrorMessages.UserNotExists.Localize(authService.Request));
        }

        protected override ApiKey GetApiKey(IRequest req, string apiKey)
        {
            var key = apiKey;
            if (string.IsNullOrWhiteSpace(key) || key == "undefined")
                key = req.Headers.Get("ApiKey");

            if (key == null || string.IsNullOrWhiteSpace(key))
                return null;

            return new ApiKey() { Id = key };
        }

    }

the method used to authenticate the token in the database is this

        public User UserDecriptedVerify(string pin)
        {
            using (var ctx = this.OpenDbConnection())
            {
                var q = ctx.From<User>()
                    .Where(u => u.Pin == pin)
                    .Take(1);
                return ctx.Single<User>(q);
            }
        }

What am I doing wrong?
Thanks
Enrico

To improve API Key Auth Performance you’ll want to enable Cached API Key Sessions otherwise each API Key Auth Request will have to perform full re-authentication:

Plugins.Add(new AuthFeature(...,
    new IAuthProvider[] {
        new ApiKeyAuthProvider(AppSettings) {
            SessionCacheDuration = TimeSpan.FromMinutes(10),
        }
    }));

The first API Auth Request will still be slow as it needs to perform the full Auth process, but subsequent requests within the session cache duration will be faster.

Note: this behavior is limited to API Key Auth, i.e. not general BearerToken Auth as JWT is much faster due to being stateless.

I tried your suggestion, but using then BearerToken and the SessionCacheDuration everytime I execute a method I receive a 401 Unauthorized. Removing the SessionCacheDuration everything works as expected.

Regards
Enrico

Are you using a very old version? as ApiKeyAuthProvider now implements async methods, e.g. AuthenticateAsync() which should be overridden instead.

Using SessionCacheDuration keeps a cache of the authenticated session in the registered ICacheClient which would prevent it from re-authenticating you may need to override PreAuthenticateWithApiKeyAsync() to debug the impl to see why it’s not restoring a previous cached version. You can use GetSessionKey(apiKey) to find the cache key the Authenticated Session should be registered against.

I’m using version 5.9.2

In my custom ApiKeyAuthProvider that method is not overridable.

How can I debug the implementation?
Regards
Enrico

Can you not step debug into the implementation? Rider will let you do this, and it looks like I’m also able to step debug with VS 2019 as well (you may need to enable Source Link support if not already), so you should be able to set breakpoints and step debug into the base implementation, here’s where the API Key Auth Provider checks for an existing session and caches it:

public override Task<bool> HasCachedSessionAsync(IRequest req, string apiSessionKey)
{
    return base.HasCachedSessionAsync(req, apiSessionKey);
}

public override Task CacheSessionAsync(IRequest req, string apiSessionKey)
{
    return base.CacheSessionAsync(req, apiSessionKey);
}

Otherwise you should be able to take a local copy of ApiKeyAuthProvider.cs and debug your own copy.

Alternatively you could download ServiceStack projects and link to the source projects.

I’d recommend upgrading to the latest v5.11 so you’re debugging an up to date version where all Auth Providers have been upgraded to use async, the v5.10 Release Notes has migration notes on Async Auth Providers.

I found it. The problem was in the IsAuthorized(session, tokens, request) method.

The original one was this

public override bool IsAuthorized(IAuthSession session, IAuthTokens tokens, Authenticate request = null)
{
   return session != null && session.IsAuthenticated && !session.UserAuthName.IsNullOrEmpty();
}

and in my AuthenticateAsync method I didn’t assign UserAuthName. Once assigned it works as expected.

Thanks!
Enrico

1 Like