content: package org.sfeir.lab.keycloak.config;
  
  import org.springframework.core.convert.converter.Converter;
  import org.springframework.security.authentication.AbstractAuthenticationToken;
  import org.springframework.security.core.GrantedAuthority;
  import org.springframework.security.core.authority.SimpleGrantedAuthority;
  import org.springframework.security.oauth2.jwt.Jwt;
  import org.springframework.security.oauth2.jwt.JwtClaimNames;
  import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
  import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
  import org.springframework.stereotype.Component;
  
  import java.util.Collection;
  import java.util.Map;
  import java.util.Set;
  import java.util.stream.Collectors;
  import java.util.stream.Stream;
  
  @Component
  public class KeycloakJwtConverter implements Converter<Jwt, AbstractAuthenticationToken> {
  
      private final JwtGrantedAuthoritiesConverter defaultJwtConverter = new JwtGrantedAuthoritiesConverter();
  
      private final JwtConverterProperties properties;
  
      public KeycloakJwtConverter(JwtConverterProperties properties) {
          this.properties = properties;
      }
  
      @Override
      public AbstractAuthenticationToken convert(Jwt source) {
          var authorities = Stream.concat(
                  defaultJwtConverter.convert(source).stream(),
                  extractResourceRoles(source).stream())
                  .collect(Collectors.toSet());
  
          return new JwtAuthenticationToken(source, authorities, getPrincipalClaimName(source));
      }
  
      private String getPrincipalClaimName(Jwt jwt) {
          String claimName = JwtClaimNames.SUB;
          if (properties.getPrincipalAttribute() != null) {
              claimName = properties.getPrincipalAttribute();
          }
          return jwt.getClaim(claimName);
      }
  
      private Collection<? extends GrantedAuthority> extractResourceRoles(Jwt jwt) {
          Map<String, Object> resourceAccess = jwt.getClaim("resource_access");
          Map<String, Object> resource;
          Collection<String> resourceRoles;
  
          if (resourceAccess == null
                  || (resource = (Map<String, Object>) resourceAccess.get(properties.getResourceId())) == null
                  || (resourceRoles = (Collection<String>) resource.get("roles")) == null) {
              return Set.of();
          }
          return resourceRoles.stream()
                  .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
                  .collect(Collectors.toSet());
      }
  }