fullstackhero/dotnet-starter-kit · error · UnauthorizedException
no current user
Error message
no current user
What it means
GetChannelByIdQueryHandler requires an authenticated caller; currentUser.GetUserId() returning Guid.Empty means no user was resolved from the JWT/context. The handler throws UnauthorizedException before doing any data access, so the request never reaches the channel lookup.
Solutions
- Refresh or re-acquire the JWT and retry with a valid Authorization: Bearer header.
- Verify the auth middleware/JWT config (issuer, audience, signing key) on the host.
- Ensure the gateway/proxy forwards the Authorization header.
- Confirm the user claim mapping (nameidentifier) is populated in the token.
Example fix
// before
fetch(`${base}/channels/${id}`);
// after
const res = await fetch(`${base}/channels/${id}`, {
headers: { Authorization: `Bearer ${await getValidAccessToken()}` }
});
if (res.status === 401) await reauthenticate(); Defensive patterns
Strategy: try-catch
Validate before calling
if (!accessToken || isTokenExpired(accessToken)) throw new Error('Not authenticated'); Type guard
const isAuthenticated = (u: unknown): u is { id: string } =>
!!u && typeof (u as any).id === 'string' && (u as any).id.length > 0; Try / catch
try { ... } catch (e) {
if (isUnauthorized(e)) { await reauthenticate(); retry(); }
else throw e;
} Prevention
- Attach a valid Bearer token to every channel request.
- Refresh tokens before expiry (proactively, not on failure only).
- Use an axios/fetch interceptor that handles 401 once, centrally.
- Verify the Authorization header isn't stripped by proxies in staging.
When it happens
Trigger: Calling GET /channels/{channelId} with a missing, malformed, or expired JWT Bearer token, or from an anonymous context where ICurrentUser.GetUserId() yields Guid.Empty.
Common situations: Token expired client-side but request still fired; Authorization header stripped by a proxy/gateway; hitting the endpoint without the [Authorize]-effective auth scheme during local testing; clock skew invalidating the JWT.
Related errors
AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15).
Data as JSON: /api/errors/4d309e9d50f901fb.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Chat/Modules.Chat/Features/v1/Channels/GetChannelById/GetChannelByIdQueryHandler.cs:21
using FSH.Modules.Chat.Contracts.v1.DTOs;
using FSH.Modules.Chat.Contracts.v1.Queries;
using FSH.Modules.Chat.Data;
using FSH.Modules.Chat.Features.v1.Internal;
using Mediator;
using Microsoft.EntityFrameworkCore;
namespace FSH.Modules.Chat.Features.v1.Channels.GetChannelById;
public sealed class GetChannelByIdQueryHandler(
ChatDbContext db,
ICurrentUser currentUser)
: IQueryHandler<GetChannelByIdQuery, ChannelDto>
{
public async ValueTask<ChannelDto> Handle(GetChannelByIdQuery q, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(q);
var userId = currentUser.GetUserId();
if (userId == Guid.Empty) throw new UnauthorizedException("no current user");
var currentUserId = userId.ToString();
var channel = await db.Channels.AsNoTracking()
.FirstOrDefaultAsync(c => c.Id == q.ChannelId, cancellationToken)
.ConfigureAwait(false)
?? throw new NotFoundException("Channel not found.");
// Private channels & DMs: must be a member. Public channels: anyone with View can see them.
if (channel.IsPrivate)
{
channel.RequireMember(currentUserId);
}
var member = channel.Members.FirstOrDefault(m => string.Equals(m.UserId, currentUserId, StringComparison.Ordinal));
int unread = 0;
if (member is not null)
{
unread = await db.Messages.AsNoTracking()View on GitHub (pinned to 3f2959e683)