{"record":{"id":"45b3d97db6f23e79","repo":"fullstackhero/dotnet-starter-kit","slug":"cannot-revoke-session-for-another-user","errorCode":null,"errorMessage":"Cannot revoke session for another user","messagePattern":"Cannot revoke session for another user","errorType":"exception","errorClass":"UnauthorizedAccessException","httpStatus":403,"severity":"error","filePath":"src/Modules/Identity/Modules.Identity/Services/SessionService.cs","lineNumber":199,"sourceCode":"        Guid sessionId,\n        string revokedBy,\n        string? reason = null,\n        CancellationToken cancellationToken = default)\n    {\n        EnsureValidTenant();\n\n        var session = await _db.UserSessions\n            .FirstOrDefaultAsync(s => s.Id == sessionId && !s.IsRevoked, cancellationToken);\n\n        if (session is null)\n        {\n            return false;\n        }\n\n        var currentUserId = _currentUser.GetUserId().ToString();\n        if (!string.Equals(session.UserId, currentUserId, StringComparison.OrdinalIgnoreCase))\n        {\n            throw new UnauthorizedAccessException(\"Cannot revoke session for another user\");\n        }\n\n        var tenantId = _multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id;\n        session.Revoke(revokedBy, reason ?? \"User requested\", tenantId);\n\n        await _db.SaveChangesAsync(cancellationToken);\n\n        if (_logger.IsEnabled(LogLevel.Information))\n        {\n            _logger.LogInformation(\"Session {SessionId} revoked by {RevokedBy}\", sessionId, revokedBy);\n        }\n\n        return true;\n    }\n\n    public async Task<int> RevokeAllSessionsAsync(\n        string userId,\n        string revokedBy,","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Identity/Modules.Identity/Services/SessionService.cs#L181-L217","documentation":"RevokeSessionAsync throws UnauthorizedAccessException when the target session's UserId does not match the currently authenticated user. Only the session owner may revoke their own session; revoking others' sessions requires an admin path.","triggerScenarios":"Calling RevokeSessionAsync(sessionId, ...) with a sessionId that belongs to another user (or with a token for a different account than the session owner).","commonSituations":"Client keeps a device/session list cached across account switches; user copies a session id from an admin tool; session row's UserId differs due to cross-tenant data copy.","solutions":["Only revoke sessions listed for the current user (fetch the user's sessions first, then revoke from that list)","Ensure the auth token belongs to the same user as the session","Use the admin revocation flow with proper permissions for other users' sessions"],"exampleFix":"// before\nawait sessionService.RevokeSessionAsync(sessionIdFromOtherUser, ct);\n// after\nvar mySessions = await sessionService.GetUserSessionsAsync(currentUser.GetUserId().ToString(), ct);\nif (mySessions.Any(s => s.Id == sessionId)) await sessionService.RevokeSessionAsync(sessionId, ct);","handlingStrategy":"validation","validationCode":"var session = await db.UserSessions.FindAsync(new object[] { sessionId }, ct);\nvar currentUserId = currentUser.GetUserId().ToString();\nif (session is null || !string.Equals(session.UserId, currentUserId, StringComparison.OrdinalIgnoreCase))\n    return Results.Forbid();","typeGuard":null,"tryCatchPattern":"try\n{\n    await sessionService.RevokeSessionAsync(sessionId, ct);\n}\ncatch (UnauthorizedAccessException)\n{\n    return Results.Forbid();\n}","preventionTips":["List the current user's sessions first and revoke only from that list","Never accept cross-user session ids from client input","Provide an admin endpoint with permission checks for revoking other users' sessions"],"tags":["authorization","sessions","identity"],"backgroundTag":"permission-denied","analyzedSha":"3f2959e683e9f83f13e55e1678c9119f63c7e8e5","analyzedAt":"2026-09-15T22:20:53.684Z","contentChangedAt":"2026-09-15T22:20:53.684Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}