fullstackhero/dotnet-starter-kit · error · UnauthorizedAccessException

Cannot view sessions for another user

Error message

Cannot view sessions for another user

What it means

GetUserSessionsAsync throws UnauthorizedAccessException when the userId parameter does not match the authenticated current user (case-insensitive comparison). Users may only list their own active sessions; admin flows must use GetUserSessionsForAdminAsync instead.

Solutions

  1. Pass the current user's id (from the auth token / CurrentUser.GetUserId()) instead of a client-supplied id
  2. For viewing other users' sessions, use the admin query (GetUserSessionsForAdminAsync) with the appropriate permission
  3. Check which account the JWT belongs to — the token may be for a different user than expected

Example fix

// before
await sessionService.GetUserSessionsAsync(userIdFromRoute, ct);
// after
var currentUserId = currentUser.GetUserId().ToString();
await sessionService.GetUserSessionsAsync(currentUserId, ct);
Defensive patterns

Strategy: validation

Validate before calling

var currentUserId = currentUser.GetUserId().ToString();
if (!string.Equals(requestedUserId, currentUserId, StringComparison.OrdinalIgnoreCase))
    return Results.Forbid();

Try / catch

try
{
    return await sessionService.GetUserSessionsAsync(userId, ct);
}
catch (UnauthorizedAccessException)
{
    return Results.Forbid();
}

Prevention

When it happens

Trigger: Calling GetUserSessionsAsync(someOtherUserId) while authenticated as a different user — e.g. passing a userId taken from a route/body controlled by the client rather than the current principal.

Common situations: Client fetches sessions from a cached/stale userId (e.g. after re-login as a different account); frontend mistakenly uses an admin-scope endpoint with a normal user token; ID casing or Guid formatting confusion.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

Thrown at src/Modules/Identity/Modules.Identity/Services/SessionService.cs:91

        if (_logger.IsEnabled(LogLevel.Information))
        {
            _logger.LogInformation("Created session {SessionId} for user {UserId}", session.Id, userId);
        }

        return MapToDto(session, isCurrentSession: true);
    }

    public async Task<List<UserSessionDto>> GetUserSessionsAsync(
        string userId,
        CancellationToken cancellationToken = default)
    {
        EnsureValidTenant();

        var currentUserId = _currentUser.GetUserId().ToString();
        if (!string.Equals(userId, currentUserId, StringComparison.OrdinalIgnoreCase))
        {
            throw new UnauthorizedAccessException("Cannot view sessions for another user");
        }

        var now = _timeProvider.GetUtcNow().UtcDateTime;
        var sessions = await _db.UserSessions
            .AsNoTracking()
            .Where(s => s.UserId == userId && !s.IsRevoked && s.ExpiresAt > now)
            .OrderByDescending(s => s.LastActivityAt)
            .ToListAsync(cancellationToken);

        return sessions.Select(s => MapToDto(s, isCurrentSession: false)).ToList();
    }

    public async Task<List<UserSessionDto>> GetUserSessionsForAdminAsync(
        string userId,
        CancellationToken cancellationToken = default)
    {
        EnsureValidTenant();

View on GitHub (pinned to 3f2959e683)