JWT Auth and MQ

Hello,

I am trying to achieve MQ authentication with JWT.
I am not sure weather this is possible as I understand there is no session persistence with JWT, but maybe there is a way to convert JWT into a session?

I have done following code:

DTO:

[Route("/Deposit", "POST")]
public class InsertDeposit : Deposit, IHasBearerToken, IReturn<InsertDepositResponse>
{
    public string BearerToken { get; set; }
}

MQ Handler:

mqServer.RegisterHandler<InsertDeposit>(m =>
{
    var req = new BasicRequest { Verb = HttpMethods.Post };
    req.Headers["X-ss-id"] = m.GetBody().BearerToken;
    var response = ((AppHostBase)appHost).ExecuteMessage(m, req);
    return response;
});

Publish MQ

...
var replyTo = mqClient.GetTempQueueName();
var insertDepositMQ = deposit.ConvertTo<InsertDeposit>();
insertDepositMQ.BearerToken = Request.GetSessionId();
mqClient.Publish(new Message<InsertDeposit>(insertDepositMQ)
{
    ReplyTo = replyTo
});
var msgResponse = mqClient.Get<InsertDepositResponse>(replyTo);
...

MQ Endpoint

[Authenticate]
public object Post(InsertDeposit request)
{
    //Here I should see user and Roles (I am trying this code:)
    if (!request.BearerToken.IsNullOrEmpty()) {
        Request.SetSessionId(request.BearerToken);
        var session = base.SessionAs<AuthUserSession>();
    }
    var deposit = request.ConvertTo<Deposit>();
    InTransaction(db => Logic.Add(deposit));
    return WithDb(db => new InsertDepositResponse { Result = Logic.GetById(deposit.Id) });
}

Currently if I add [Authenticate] as shown above, I cannot get into that function, if I remove [Authenticate] then I can get into it.

I also tried with X-ss-tok instead of X-ss-id.

Thank you.

See docs on Authenticated Requests via MQ. The recommended way is to have your Request DTO implement IHasBearerToken and populate its BearerToken with the JWT.

Otherwise Bearer Tokens are typically sent via the HTTP Authorization HTTP Header, e.g:

new BasicRequest { Authorization = $"Bearer {jwt}" }

Wait are you already sending in the BearerToken? And you’re saying the default behavior doesn’t authenticate? As this is supported by default:

mqServer.RegisterHandler<InsertDeposit>(ExecuteMessage);

Where you should be able to retrieve your session as normal in your Service, e.g:

var session = base.SessionAs<AuthUserSession>();
1 Like

OK Thanks, I replaced this:

var req = new BasicRequest { Verb = HttpMethods.Post };
req.Headers["X-ss-id"] = m.GetBody().BearerToken;

with this:

var req = new BasicRequest { Authorization = $"Bearer {m.GetBody().BearerToken}",
                             Verb = HttpMethods.Post };
// req.Headers["X-ss-id"] = m.GetBody().BearerToken;

And I also have this method to publish a message in sync way, where I then extracted the token from the current request’s authorization property and set BearerToken to it:

public object Publish<T, R>(object toPublish)
{
    using (var mqClient = MQServer.CreateMessageQueueClient())
    {
        var replyTo = mqClient.GetTempQueueName();

        var dto = toPublish.ConvertTo<T>();

        if (dto is IHasBearerToken)
        {
            var splitAuthHeader = Request.Authorization.Split(' ');
            if (splitAuthHeader.Length > 0)
                (dto as IHasBearerToken).BearerToken = splitAuthHeader[1];
        }

        mqClient.Publish(new Message<T>(dto)
        {
            ReplyTo = replyTo
        });

        var msgResponse = mqClient.Get<R>(replyTo);

        var status = msgResponse?.Body?.GetResponseStatus();
        if (status?.ErrorCode != null)
            throw new KnownError(status.Message);

        return msgResponse?.Body;
    }
}

Thanks it is now working.

FYI

if (dto is IHasBearerToken)
{
    var splitAuthHeader = Request.Authorization.Split(' ');
    if (splitAuthHeader.Length > 0)
        (dto as IHasBearerToken).BearerToken = splitAuthHeader[1];
}

Is better rewritten as:

if (dto is IHasBearerToken hasBearer) 
    hasBearer.BearerToken = Request.GetBearerToken();

Where it supports other ways Bearer Tokens can be assigned on requests.

1 Like