Autoquery Custom authentication doesn't work on linux

This below code works perfectly fine on local test IIS express server, it will return http code 401. however when deployed to linux server, the response is 200 with data without any authorization header.

public async Task<object> Any(QueryMerchantCustomers qry)
{
    // logging
    try
    {
        var json = JsonConvert.SerializeObject(Request.Authorization);
        var filePath = Path.Combine(Directory.GetCurrentDirectory(), $"{Guid.NewGuid()}.json");
        await System.IO.File.WriteAllTextAsync(filePath, json);
    }
    catch (Exception ex)
    {
        // Handle any errors that may occur while writing the file
        Log.Error(ex, "Failed to write txn to local file.");
    }
    if (!_authHandler.VerifyJwt(Request, out var claimsPrincipal, "user", qry.MerchantGuid) && !base.Request.IsLocal)
    {
        //throw new HttpError(HttpStatusCode.Unauthorized, "Unauthorized");
        base.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
        base.Response.EndRequest();
    }
    var res = new QueryResponse<Customer>();
    var customers = new List<Customer>();
    if (string.IsNullOrEmpty(qry.MerchantGuid))
        return res.AddError("Merchant guid can not be null or empty");
    var merchant = await _jointMerchantHandler.GetMerchantByGuidAsync(qry.MerchantGuid);
    // make it re-usable in future
    if (qry.Page > 0 && qry.Limit > 0)
    {
        qry.Page -= 1;
        qry.Skip = qry.Page * qry.Limit;
        qry.Take = qry.Limit;
    }
    var q = AutoQuery.CreateQuery(qry, base.Request);
    q.And<UserDetail>(x => x.LicenseId == merchant.PrimaryLicenseId && !x.IsDelete);
    var result = AutoQuery.Execute(qry, q);
    if (result.Results.Count == 0) return res;
    var details = _userDetailRepo.Select(x => x.LicenseId == merchant.PrimaryLicenseId && Sql.In(x.UserId, result.Results.Select(x => x.Id).ToList()));
    foreach (var user in result.Results)
        customers.Add(user.ToCustomer().MergeDetail(details.FirstOrDefault(x => x.UserId == user.Id && !x.IsDelete)));
    res.ResponseStatus = result.ResponseStatus;
    res.Meta = result.Meta;
    res.Offset = result.Offset;
    res.Total = result.Total;
    res.Results = customers;
    base.Response.AddHeader("x-aq-sql", System.Text.RegularExpressions.Regex.Escape(q.ToMergedParamsSelectStatement()));
    return res;
}

What is _authHandler and what’s the implementation of VerifyJwt? Do you know exactly what behavior is different under Linux?

The behavior is it doesn’t end request in ubuntu server 18.04 LTS, but it does end and response 401 in IIS Express on windows 11 machine.

_authHandler.VerifyJwt

public bool VerifyJwt(IRequest req,  out ClaimsPrincipal claimsPrincipal, string role = null, string merchantGuid = null)
{
    var requirement = new RoleAccessibilityRequirement(role);
    claimsPrincipal = new ClaimsPrincipal();
    Log.Logger.Debug($@"token ${req.Authorization}");
    if (req.Authorization != null && req.Authorization.StartsWith("Bearer "))
    {
        
        // Get Token
        var token = req.Authorization.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries)[1]?.Trim();
        var validated = _ssJwtHandler.ValidateToken(token, out claimsPrincipal);
        Log.Logger.Debug( $@"token ${token}");
        if (string.IsNullOrEmpty(role)) return validated;
        else
        {
            validated = false;
            string merchantId = null;
            if (merchantGuid != null) merchantId = _merchantManager.GetCacheableMerchantAsync(merchantGuid).GetAwaiter().GetResult()?.LicenseId.ToString();
            if (merchantId != null) validated = RoleAccessibilityHandler.ValidateRequirement(claimsPrincipal, requirement,merchantId);
            return validated;
        }

    }
    return false;
}

This looks like a Custom Auth implementation? Where is the issue in ServiceStack?

Yes. but on linux, base.Response.EndRequest(); doesn’t end. I tried throw new HttpError(HttpStatusCode.Unauthorized, “Unauthorized”);, it is also not working. I am referring to this docs Customize HTTP Responses · stulife/ServiceStack Wiki · GitHub

It’s not going to short-circuit the method implementation, i.e. you should also return from the method.

base.Response.EndRequest();
return null;

Otherwise you can throw an Exception to short-circuit execution as you were doing in comments:

throw HttpError.Unauthorized("Unauthorized");
//throw new HttpError(HttpStatusCode.Unauthorized, "Unauthorized");

Api server is using ServiceStack 6.1.0

I tried that before. I will try it again.

return null or throw HttpError both are NOT working.

If it’s still returning a response, it suggests your VerifyJwt() implementation isn’t returning the expected response.

Thank you. I think it is my code issue… Thanks for your lovely and speedy reply… have a good day.

1 Like