public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
        {
            // retrieve controller object
            var controller = context.ActionContext.ControllerContext.Controller as BaseController;

            if (controller == null)
            {
                throw new InvalidOperationException("Controller must inherit from BaseController class!");
            }

            // check basic authentication
            var auth = context.Request.Headers.Authorization;

            if (auth != null && auth.Scheme == "Basic" && !string.IsNullOrEmpty(auth.Parameter))
            {
                // parse the authorization header
                string login, password;
                if (ParseBasicAuthParameter(auth.Parameter, out login, out password))
                {
                    // authenticate by password
                    try
                    {
                        controller.CallContext.CurrentUser = await _authenticationManager.AuthenticateByPasswordAsync(login, password);
                    }
                    catch (AuthenticationException)
                    {
                    }
                }

                return;
            }

            // check access key authentication
            if (auth != null && auth.Scheme == "Bearer" && !string.IsNullOrEmpty(auth.Parameter))
            {
                // get the token value
                var token = auth.Parameter;

                // get the access key object
                var accessKey = controller.DataContext.AccessKey.Get(token);
                if (accessKey != null && (accessKey.ExpirationDate == null || accessKey.ExpirationDate > DateTime.UtcNow))
                {
                    // get the user object
                    var user = controller.DataContext.User.Get(accessKey.UserID);
                    if (user != null && user.Status == (int)UserStatus.Active)
                    {
                        // prolongate the key
                        if (accessKey.Type == (int)AccessKeyType.Session && accessKey.ExpirationDate != null &&
                            (accessKey.ExpirationDate.Value - DateTime.UtcNow).TotalSeconds < _deviceHiveConfiguration.Authentication.SessionTimeout.TotalSeconds / 2)
                        {
                            accessKey.ExpirationDate = DateTime.UtcNow.Add(_deviceHiveConfiguration.Authentication.SessionTimeout);
                            controller.DataContext.AccessKey.Save(accessKey);
                        }

                        // authenticate the user
                        controller.CallContext.CurrentAccessKey = accessKey;
                        controller.CallContext.CurrentUser      = user;
                    }
                }

                return;
            }

            // check device authentication
            var deviceId = context.Request.GetCustomHeader("Auth-DeviceID");

            if (!string.IsNullOrEmpty(deviceId))
            {
                // get the device object
                var device = controller.DataContext.Device.Get(deviceId);
                if (device != null && device.Key != null)
                {
                    // check device key authentication
                    var authDeviceKey = context.Request.GetCustomHeader("Auth-DeviceKey");
                    if (authDeviceKey != null && device.Key == authDeviceKey)
                    {
                        // ensure the device is not blocked
                        if (device.IsBlocked)
                        {
                            throw new HttpResponseException(context.Request.CreateResponse(
                                                                HttpStatusCode.Forbidden, new ErrorDetail(11, "Device has been blocked")));
                        }

                        // authenticate the device and update last online
                        controller.CallContext.CurrentDevice = device;
                        controller.DataContext.Device.SetLastOnline(device.ID);
                    }
                }

                return;
            }
        }