Listing 1: Abhängigkeiten in Maven festlegen
<dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.keycloak.bom</groupId>
        <artifactId>keycloak-adapter-bom</artifactId>
        <version>18.0.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
</dependencyManagement>
...
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-spring-boot-starter</artifactId>
</dependency>

-----

Listing 2: Keycloak konfigurieren
keycloak:
    realm: customer
    resource:  customer-service
    auth-server-url: http://localhost:9090/auth
    use-resource-role-mappings: true
    public-client: true
    principal-attribute: preferred_username
    security-constraints:
        - authRoles:
            - user
          securityCollections:
            - patterns:
                - customers/*

-----

Listing 3: Konfiguration bekannt machen
@Configuration
public class KeycloakConfig {

    @Bean
    public KeycloakSpringBootConfigResolver keycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }
}

-----

Listing 4: Maven-Konfiguration REST-Client
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security.oauth.boot</groupId>
    <artifactId>spring-security-oauth2-autoconfigure</artifactId>
    <version>2.5.2</version>
</dependency>

-----

Listing 5: Client für Keycloak konfigurieren
auth:
    url: http://localhost:9090/auth/realms/customer/protocol/openid-connect/token
    clientId: customer-service
    clientSecret: ...

-----

Listing 6: RestTemplate erzeugen
@Service
@Slf4j
public class KeycloakService {

    @Value( "${auth.url}" )
    private String realm;

    @Value( "${auth.clientId}" )
    private String client;

    @Value( "${auth.clientSecret}" )
    private String secret;

    @Bean
    public RestTemplate createClient() {
        ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
        resourceDetails.setGrantType(OAuth2Constants.CLIENT_CREDENTIALS);
        resourceDetails.setAccessTokenUri(url);
        resourceDetails.setClientId(client);
        resourceDetails.setClientSecret(secret);
        return new OAuth2RestTemplate(resourceDetails);
    }
}

-----

Listing 7: OIDC-Claims
{
    "sub": "1234567890",
    "name": "John Doe",
    "email": "john.doe@example.com",
    "roles": [
        "ADMIN"
    ],
    "locale": "en-US",
    "preferred_username": "john.doe@example.com",
    "sub": "00u9vme99nxudvxZA0h7",
    "updated_at": 1490198843,
    "zoneinfo": "America/Los_Angeles"
}

-----

Listing 8: Token Exchange freigeben
docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -e JAVA_OPTS_APPEND="-Dkeycloak.profile.feature.token_exchange=enabled -Dkeycloak.profile.feature.admin_fine_grained_authz=enabled" quay.io/keycloak/keycloak:18.0.0 start-dev
...
Appending additional Java properties to JAVA_OPTS: -Dkeycloak.profile.feature.token_exchange=enabled -Dkeycloak.profile.feature.admin_fine_grained_authz=enabled
Updating the configuration and installing your custom providers, if any. Please wait.
2022-05-13 09:33:45,519 INFO  [org.keycloak.common.Profile] (build-100) Preview feature enabled: admin_fine_grained_authz
2022-05-13 09:33:45,567 INFO  [org.keycloak.common.Profile] (build-100) Preview feature enabled: token_exchange
2022-05-13 09:33:53,990 INFO  [io.quarkus.deployment.QuarkusAugmentor] (main) Quarkus augmentation completed in 11162ms

-----

Listing 9: Anfrage aus Clientsicht
CLIENT_ACCESS_TOKEN=$(curl -X POST \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d 'grant_type=client_credentials&client_id='"$CLIENT_ID"'&client_secret='"$CLIENT_SECRET" \
    "http://localhost:8080/auth/realms/$REALM_NAME/protocol/openid-connect/token" \
    | jq -r '.access_token')

-----

Listing 10: Tokenaustausch
curl -X POST \
    -d "client_id=$CLIENT_ID" \
    -d "client_secret=$CLIENT_SECRET" \
    --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
    -d "subject_token=$CLIENT_ACCESS_TOKEN" \
    -d "subject_issuer=http://localhost:8080/auth/realms/%REALM_NAME" \
    --data-urlencode "subject_token_type=urn:ietf:params:oauth:token-type:access_token" \
    -d "audience=$INTERNAL_CLIENT_ID" \
    http://localhost:8080/auth/realms/$REALM_NAME/protocol/openid-connect/token
