Dynamically remove library based on user role, cache context not working I want to remove all libraries of modules &amp; themes, except those from modules/themes that are defined by me.
This should only be done for anonymous users. All libraries should be served to authenticated users.

I'm adding the user.roles cache context in the html preprocess hook and remove all library definitions that are not desired:

/**
 * Implements hook_preprocess_html().
 */
function mytheme_preprocess_html(array &amp;$variables) {
  $variables['page']['#cache']['contexts'][] = 'user.roles';
}

/**
 * Implements hook_library_info_alter().
 */
function mytheme_library_info_alter(array &amp;$libraries, $module) {
  /* Remove all libraries that are not needed.
  Only remove them for anonymous users, since a lot of libraries are required for the admin interface to work. */
  $allowed_modules_with_libraries = [
    'mytheme',
    'google_tag',
    'my_custom_module',
  ];

  if (!in_array($module, $allowed_modules_with_libraries) &amp;&amp; !Drupal::currentUser()-&gt;isAuthenticated()) {
    $libraries = [];
  }
}


My problem is, that the attached libraries are not completely separated by user role cache context:

My test workflow:


Clear all caches
Requesting page as authenticated user
Contrib assets in browser sources panel:




This is as expected.


Requesting same page as anonymous user
Contrib assets in browser sources panel:




This is not as expected, nothing should be present here.

The other way around:


Clear all caches


Requesting page as anonymous user
No contrib assets are displayed browser sources panel.



This is as expected.


Requesting same page as authenticated user
Assets in browser sources panel:




This is not as expected, paragraphs and webform assets are missing.

The x-drupal-cache-contexts HTTP response header content: languages:language_content languages:language_interface languages:language_url route session theme timezone url.path url.query_args user

The user cache context is there, shouldn't the response be cached by user (including the role) then?

I tried doing this by using hook_page_attachments_alter, but not all libraries that are attached to the response are listed there.
I'm not sure if changing the library definitions with hook_library_info_alter is the right approach. Since I don't want to change the libraries. I just want to detach them from the response.

The page_cache and dynamic_page_cache modules are enabled.
hook_library_info_alter() is not the right approach. You get the role of the user who installs a module or clears the cache, not of the user who requests the page. Info alter hooks in general are about changing information provided by other extensions and usually are only recalculated if an extension is added or removed and for a better dev experience on a cache clear. 

And indeed, hook_page_attachments_alter() lists only libraries added by other hook_page_attachments(_alter) hooks. See invokePageAttachmentHooks(), which starts with an empty attachments array:

  public function invokePageAttachmentHooks(array &amp;$page) {
    // Modules can add attachments.
    $attachments = [];
    ...


So we can rule out both hooks you've mentioned. Attached libraries are collected from many different places (YAML, render arrays, hooks) and they are merged (bubbled up) through the entire page building and rendering process. So it might be a good idea to attach the override in form of a custom library the same  way and let Drupal calculate the assets when rendering the page. See https://www.drupal.org/node/2216195#override-extend