fullstackhero/dotnet-starter-kit · error · UnauthorizedException

no current user

Error message

no current user

What it means

SendMessageCommandHandler requires an authenticated user before sending a message. It calls ICurrentUser.GetUserId(); when the JWT/context carries no user (or an empty Guid), it throws UnauthorizedException("no current user") instead of attempting to persist a message with no sender.

Solutions

  1. Ensure the caller sends a valid Bearer token (log in first; refresh if expired).
  2. Verify UseAuthentication/UseAuthorization ordering in the host pipeline.
  3. Check that the endpoint requires authorization (no [AllowAnonymous]) and the JWT bearer options (Authority, Audience) are correct.
  4. If invoked server-side (job/hub), propagate the user's claims/token into the call context.

Example fix

// before
fetch('/api/v1/channels/'+id+'/messages', { method: 'POST', body })
// after
fetch('/api/v1/channels/'+id+'/messages', { method: 'POST', headers: { Authorization: `Bearer ${accessToken}` }, body })
Defensive patterns

Strategy: validation

Validate before calling

const token = await getAccessToken();
if (!token) throw new Error('Login required before sending messages');

Try / catch

try { await sendMessage(cmd); }
catch (e) { if (e.status === 401) { await relogin(); retry(); } else throw e; }

Prevention

When it happens

Trigger: POST to the send-message endpoint without a valid JWT, with an expired/anonymous token, or on an endpoint misconfigured to allow anonymous access so ICurrentUser resolves to Guid.Empty.

Common situations: Missing Authorization header in the client, expired access token, JWT authentication middleware not registered/ordered correctly, calling the endpoint from a background job or SignalR context without forwarding the user's token.

Related errors


AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15). Data as JSON: /api/errors/f3fbfed2e4b2f9a7. Report an issue: GitHub.

Appendix: source

Thrown at src/Modules/Chat/Modules.Chat/Features/v1/Messages/SendMessage/SendMessageCommandHandler.cs:32

using Mediator;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;

namespace FSH.Modules.Chat.Features.v1.Messages.SendMessage;

public sealed class SendMessageCommandHandler(
    ChatDbContext db,
    ICurrentUser currentUser,
    IHubContext<AppHub> hub,
    IMentionResolver mentionResolver,
    IEventBus eventBus)
    : ICommandHandler<SendMessageCommand, MessageDto>
{
    public async ValueTask<MessageDto> Handle(SendMessageCommand cmd, CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(cmd);
        var userId = currentUser.GetUserId();
        if (userId == Guid.Empty) throw new UnauthorizedException("no current user");
        var currentUserId = userId.ToString();

        var channel = await db.Channels.FirstOrDefaultAsync(c => c.Id == cmd.ChannelId, cancellationToken)
            .ConfigureAwait(false)
            ?? throw new NotFoundException("Channel not found.");

        channel.RequireMember(currentUserId);

        Message? parent = null;
        if (cmd.ParentMessageId is { } parentId)
        {
            parent = await db.Messages.FirstOrDefaultAsync(m => m.Id == parentId, cancellationToken)
                .ConfigureAwait(false)
                ?? throw new NotFoundException("Parent message not found.");
            if (parent.ChannelId != channel.Id)
            {
                throw new CustomException("Parent message belongs to a different channel.", (IEnumerable<string>?)null, HttpStatusCode.BadRequest);
            }

View on GitHub (pinned to 3f2959e683)