{"record":{"id":"1e0ff653b6424e18","repo":"fullstackhero/dotnet-starter-kit","slug":"no-current-user-unpinmessagecommandhandler","errorCode":null,"errorMessage":"no current user","messagePattern":"no current user","errorType":"exception","errorClass":"UnauthorizedException","httpStatus":401,"severity":"error","filePath":"src/Modules/Chat/Modules.Chat/Features/v1/Messages/UnpinMessage/UnpinMessageCommandHandler.cs","lineNumber":23,"sourceCode":"using FSH.Modules.Chat.Data;\nusing FSH.Modules.Chat.Features.v1.Internal;\nusing Mediator;\nusing Microsoft.AspNetCore.SignalR;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace FSH.Modules.Chat.Features.v1.Messages.UnpinMessage;\n\npublic sealed class UnpinMessageCommandHandler(\n    ChatDbContext db,\n    ICurrentUser currentUser,\n    IHubContext<AppHub> hub)\n    : ICommandHandler<UnpinMessageCommand, Unit>\n{\n    public async ValueTask<Unit> Handle(UnpinMessageCommand cmd, CancellationToken cancellationToken)\n    {\n        ArgumentNullException.ThrowIfNull(cmd);\n        var userId = currentUser.GetUserId();\n        if (userId == Guid.Empty) throw new UnauthorizedException(\"no current user\");\n        var currentUserId = userId.ToString();\n\n        var message = await db.Messages.FirstOrDefaultAsync(m => m.Id == cmd.MessageId, cancellationToken)\n            .ConfigureAwait(false)\n            ?? throw new NotFoundException(\"Message not found.\");\n\n        var channel = await db.Channels.FirstOrDefaultAsync(c => c.Id == message.ChannelId, cancellationToken)\n            .ConfigureAwait(false)\n            ?? throw new NotFoundException(\"Message not found.\");\n        channel.RequireMember(currentUserId);\n\n        message.Unpin(currentUserId);\n        await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);\n\n        await hub.Clients.Group($\"channel:{channel.Id}\")\n            .SendAsync(\"ChatMessageUnpinned\", message.ToDto(), cancellationToken)\n            .ConfigureAwait(false);\n        return Unit.Value;","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Chat/Modules.Chat/Features/v1/Messages/UnpinMessage/UnpinMessageCommandHandler.cs#L5-L41","documentation":"UnpinMessageCommandHandler first resolves the current user; if ICurrentUser.GetUserId() returns Guid.Empty (no authenticated principal) it throws UnauthorizedException(\"no current user\") before touching the message.","triggerScenarios":"Calling the unpin endpoint without a valid JWT, with an expired token, or from a context without user claims (background job, unauthenticated SignalR call).","commonSituations":"Token expired while the client was idle, Authorization header dropped by a proxy, endpoint accidentally marked AllowAnonymous so identity never populates.","solutions":["Re-authenticate and resend with a fresh Bearer token.","Verify auth middleware ordering and that the endpoint requires authorization.","If server-side, forward the originating user's token/claims.","Check the JWT is validated against the correct Authority/Audience so claims map to ICurrentUser."],"exampleFix":"// before\nclient.defaults.headers.common.Authorization = undefined; // accidentally cleared\n// after\nclient.defaults.headers.common.Authorization = `Bearer ${await getValidAccessToken()}`;","handlingStrategy":"validation","validationCode":"if (!(await getAccessToken())) throw new Error('Login required to unpin messages');","typeGuard":null,"tryCatchPattern":"try { await unpinMessage(id); }\ncatch (e) { if (e.status === 401) { await reauth(); retry(); } else throw e; }","preventionTips":["Central token refresh in the API client","Require authorization on mutation endpoints","Forward user tokens in server-side/realtime calls"],"tags":["auth","chat","jwt"],"backgroundTag":"authentication-required","analyzedSha":"3f2959e683e9f83f13e55e1678c9119f63c7e8e5","analyzedAt":"2026-09-15T22:20:53.684Z","contentChangedAt":"2026-09-15T22:20:53.684Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}