Skip to content

dasniko/testcontainers-keycloak

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

385 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Keycloak Testcontainer

Spin up a real Keycloak OAuth2/OIDC identity provider as a Docker container in your Java integration tests — no mocks, no manual setup. Built on Testcontainers, it works with JUnit 5 and integrates seamlessly with Spring Boot, Quarkus, and any other Java framework. New here? → Quick Start

GitHub Release Maven Central GitHub Release Date Github Last Commit License

Keycloak Version Java Version GitHub Stars CI build

Setup

The release versions of this project are available at Maven Central.

Maven:

<dependency>
  <groupId>com.github.dasniko</groupId>
  <artifactId>testcontainers-keycloak</artifactId>
  <version>VERSION</version>
  <scope>test</scope>
</dependency>

Gradle (Kotlin DSL):

testImplementation("com.github.dasniko:testcontainers-keycloak:VERSION")

Tip

There is also a 999.0.0-SNAPSHOT version available, pointing to the nightly Docker image by default and using the 999.0.0-SNAPSHOT Keycloak libraries as dependencies.

Version Compatibility

Important

See version overview for an overview of which Keycloak release works with this library by default and which Testcontainers version is used. This library is, like Keycloak, only developed in the forward direction — no LTS, no backports. Make sure to stay up to date.

Contents

How to use

The @Container annotation used here in the readme is from the JUnit 5 support of Testcontainers. Please refer to the Testcontainers documentation for more information.

Default (deprecated)

Important

Starting with version 4.2, the default constructor is deprecated and should no longer be used. Please use the new KeycloakContainer(String imageName) constructor instead (see section Custom image below). The behavior of the default constructor will most likely change in future versions!

Simply spin up a default Keycloak instance:

@Container
KeycloakContainer keycloak = new KeycloakContainer();

Custom image

Use a distinct Keycloak Docker image/version:

@Container
KeycloakContainer keycloak = new KeycloakContainer("quay.io/keycloak/keycloak:26.4");

Initial admin user credentials

Use different admin credentials than the default internal (admin/admin) ones:

@Container
KeycloakContainer keycloak = new KeycloakContainer("kcImageName:tag")
    .withAdminUsername("myKeycloakAdminUser")
    .withAdminPassword("tops3cr3t");

Realm Import

Power up a Keycloak instance with one or more existing realm JSON config files (from classpath):

@Container
KeycloakContainer keycloak = new KeycloakContainer("kcImageName:tag")
    .withRealmImportFile("/test-realm.json");

or

    .withRealmImportFiles("/test-realm-1.json", "/test-realm-2.json");

If your realm JSON configuration file includes user definitions - particularly the admin user for the master realm - ensure you disable the automatic bootstrapping of the admin user:

@Container
KeycloakContainer keycloak = new KeycloakContainer("kcImageName:tag")
    .withBootstrapAdminDisabled()
    .withRealmImportFile("/test-realm.json");

To retrieve a working Keycloak Admin Client from the container, make sure to override the admin credentials to match those in your imported realm JSON configuration file:

@Container
KeycloakContainer keycloak = new KeycloakContainer("kcImageName:tag")
    .withBootstrapAdminDisabled()
    .withRealmImportFile("/test-realm.json")
    .withAdminUsername("myKeycloakAdminUser")
    .withAdminPassword("tops3cr3t");

Getting an admin client and other information from the testcontainer

You can get an instance of org.keycloak.admin.Keycloak admin client directly from the container, using

org.keycloak.admin.Keycloak keycloakAdmin = keycloakContainer.getKeycloakAdminClient();

The admin client is configured with current admin credentials.

Note

The org.keycloak:keycloak-admin-client package is a transitive dependency of this project, ready to be used by you in your tests, no need to add it on your own.

You can also get several properties from the Keycloak container:

String authServerUrl = keycloak.getAuthServerUrl();
String adminUsername = keycloak.getAdminUsername();
String adminPassword = keycloak.getAdminPassword();

with these properties, you can create e.g. a custom org.keycloak.admin.client.Keycloak object to connect to the container and do optional further configuration:

Keycloak keycloakAdminClient = KeycloakBuilder.builder()
    .serverUrl(keycloak.getAuthServerUrl())
    .realm(KeycloakContainer.MASTER_REALM)
    .clientId(KeycloakContainer.ADMIN_CLI_CLIENT)
    .username(keycloak.getAdminUsername())
    .password(keycloak.getAdminPassword())
    .build();

Context Path

As Keycloak comes with the default context path /, you can set your custom context path, e.g. for compatibility reasons to previous versions, with:

@Container
KeycloakContainer keycloak = new KeycloakContainer("kcImageName:tag")
    .withContextPath("/auth");

Management Port

Starting from Keycloak version 25.0.0, Keycloak will propagate /health and /metrics on "Management Port", see Configuring the Management Interface and Migration Guide

KeycloakContainer keycloak = new KeycloakContainer("kcImageName:tag").withEnabledMetrics();
keycloak.start();
keycloak.getMgmtServerUrl();

Memory Settings

As of Keycloak 24 the container doesn't use an absolute amount of memory, but a relative percentage of the overall available memory to the container, see also here.

This testcontainer has an initial memory setting of

JAVA_OPTS_KC_HEAP="-XX:InitialRAMPercentage=1 -XX:MaxRAMPercentage=5"

to not overload your environment. You can override this setting with the withRamPercentage(initial, max) method:

@Container
KeycloakContainer keycloak = new KeycloakContainer("kcImageName:tag")
    .withRamPercentage(50, 70);

TLS (SSL) Usage

You have three options to use HTTPS/TLS secured communication with your Keycloak Testcontainer.

Built-in TLS Keystore

This Keycloak Testcontainer comes with built-in TLS certificate (tls.crt), key (tls.key) and Java KeyStore (tls.jks) files, located in the resources folder. You can use this configuration by only configuring your testcontainer like this:

@Container
KeycloakContainer keycloak = new KeycloakContainer("kcImageName:tag").useTls();

The password for the provided Java KeyStore file is changeit. See also KeycloakContainerHttpsTest.shouldStartKeycloakWithProvidedTlsKeystore.

The method getAuthServerUrl() will then return the HTTPS url.

Custom TLS Cert and Key

Of course you can also provide your own certificate and key file for usage in this Testcontainer:

@Container
KeycloakContainer keycloak = new KeycloakContainer("kcImageName:tag")
    .useTls("your_custom.crt", "your_custom.key");

See also KeycloakContainerHttpsTest.shouldStartKeycloakWithCustomTlsCertAndKey.

The method getAuthServerUrl() will also return the HTTPS url.

Custom TLS Keystore

Last but not least, you can also provide your own keystore file for usage in this Testcontainer:

@Container
KeycloakContainer keycloak = new KeycloakContainer("kcImageName:tag")
    .useTlsKeystore("your_custom.jks", "password_for_your_custom_keystore");

See also KeycloakContainerHttpsTest.shouldStartKeycloakWithCustomTlsKeystore.

The method getAuthServerUrl() will also return the HTTPS url.

Keycloak Feature Flags

You can enable and disable Keycloak feature flags on your Testcontainer:

@Container
KeycloakContainer keycloak = new KeycloakContainer("kcImageName:tag")
    .withFeaturesEnabled("docker", "scripts", "...")
    .withFeaturesDisabled("authorization", "impersonation", "...");

Custom CLI Config arguments

All default configurations in this Testcontainer is done through environment variables. You can overwrite and/or add config settings on command-line-level (cli args) with this method:

@Container
KeycloakContainer keycloak = new KeycloakContainer("kcImageName:tag")
    .withCustomCommand("--hostname=keycloak.local");

A warning will be printed to the log output when custom command parts are being used, so that you are aware that you are responsible on your own for proper execution of this container.

Starting in production mode

By default, the container is started in dev mode (start-dev). If needed you can enable production mode:

@Container
KeycloakContainer keycloak = new KeycloakContainer("kcImageName:tag")
    .withProductionMode();

Optimized flag

It is possible that you use your own pre-build image with the --optimized flag. Setting this option will implicitly enable production mode!

@Container
KeycloakContainer keycloak = new KeycloakContainer("<YOUR_IMAGE>" + ":<YOUR_TAG>")
    .withOptimizedFlag();

Note

If you don't enable the health endpoint in your custom image, the container will not be healthy. In this case please provide your own waitStrategy.

Check out the tests at KeycloakContainerOptimizedTest.

Testing Custom Extensions

To ease extension testing, you can tell the Keycloak Testcontainer to detect extensions in a given classpath folder. This allows to test extensions directly in the same module without a packaging step.

If you have your Keycloak extension code in the src/main/java folder, then the resulting classes will be generated to the target/classes folder. To test your extensions you just need to tell KeycloakContainer to consider extensions from the target/classes folder.

Keycloak Testcontainer will then dynamically generate a packaged jar file with the extension code that is then picked up by Keycloak.

KeycloakContainer keycloak = new KeycloakContainer("kcImageName:tag")
    .withProviderClassesFrom("target/classes");

For your convenience, there's now (since 3.3) a default method, which yields to target/classes internally:

KeycloakContainer keycloak = new KeycloakContainer("kcImageName:tag")
    .withDefaultProviderClasses();

See also KeycloakContainerExtensionTest class.

Dependencies & 3rd-party Libraries

If you need to provide any 3rd-party dependency or library, you can do this with

List<File> libs = ...;
KeycloakContainer keycloak = new KeycloakContainer("kcImageName:tag")
    .withProviderLibsFrom(libs);

You have to provide a list of resolvable Files.

Tip

If you want/need to use dependencies from e.g., Maven (or Gradle), you can use ShrinkWrap Resolvers. See, as an example, how this is used at the KeycloakContainerExtensionTest#shouldDeployProviderWithDependencyAndCallCustomEndpoint() test.

Extending KeycloakContainer

In case you need a custom implementation of the default KeycloakContainer, you should inherit from ExtendableKeycloakContainer. This allows to set the generics and use your custom implementation without the need for type casts.

public class MyCustomKeycloakContainer extends ExtendableKeycloakContainer<MyCustomKeycloakContainer> {
  public MyCustomKeycloakContainer() {
    super("kcImageName:tag");
  }
  public MyCustomKeycloakContainer(String dockerImageName) {
    super(dockerImageName);
  }
}

...

MyCustomKeycloakContainer keycloakContainer = new MyCustomKeycloakContainer()
    .withAdminPassword("password");

Remote Debugger Support

You can tell the Keycloak Testcontainer to open a debug port for attaching a remote debugger.

This command will enable remote debugging in Keycloak and expose the used debug port in the container on a random port to the outside:

KeycloakContainer keycloak = new KeycloakContainer("kcImageName:tag")
    .withDebug();

If you want to enable remote debugging on a fixed port and optionally have Keycloak wait (suspend) until a debugger has attached to this port, use this command:

KeycloakContainer keycloak = new KeycloakContainer("kcImageName:tag")
    .withDebugFixedPort(int hostPort, boolean suspend);

Usage in your application framework tests

A common question is how to configure your test setup when you're used to specifying fixed ports in properties or YAML files. With Testcontainers you don't need fixed ports — each framework provides a way to dynamically configure your application context after the container starts.

Spring Boot

The recommended approach is @DynamicPropertySource, which injects the container's dynamic URLs into the Spring Environment before the application context starts. For example:

@Testcontainers
@SpringBootTest
class MyTest {

    @Container
    static KeycloakContainer keycloak = new KeycloakContainer("quay.io/keycloak/keycloak:26.4")
        .withRealmImportFile("/test-realm.json");

    @DynamicPropertySource
    static void keycloakProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.security.oauth2.resourceserver.jwt.issuer-uri",
            () -> keycloak.getAuthServerUrl() + "/realms/test");
    }
}

Full Spring Boot integration guide — covers OAuth2 resource server, OAuth2 client, shared container patterns, token acquisition, and TLS.

Quarkus

Implement QuarkusTestResourceLifecycleManager to start the container and inject config properties before the Quarkus application context boots:

public class KeycloakTestResource implements QuarkusTestResourceLifecycleManager {

    private static final KeycloakContainer keycloak =
        new KeycloakContainer("quay.io/keycloak/keycloak:26.4")
            .withRealmImportFile("/test-realm.json");

    @Override
    public Map<String, String> start() {
        keycloak.start();
        return Map.of(
            "quarkus.oidc.auth-server-url", keycloak.getAuthServerUrl() + "/realms/test",
            "quarkus.oidc.client-id", "my-client"
        );
    }

    @Override
    public void stop() { keycloak.stop(); }
}

Full Quarkus integration guide — covers OIDC resource server, OIDC client, multi-tenant setups, container injection into tests, and TLS.

Others

Consult the docs of your application framework on how to dynamically configure your stack for testing.

YouTube Videos about Keycloak Testcontainers

Integration Tests with Keycloak & Testcontainers Keycloak DevDay 2024: Extensions Development with Testcontainers-Keycloak Testing Keycloak extensions using Testcontainers
Integration Tests with Keycloak & Testcontainers Keycloak DevDay 2024: Extensions Development with Testcontainers-Keycloak Testing Keycloak extensions using Testcontainers (Keycloak Hour of Code)

Credits

Many thanks to the creators and maintainers of Testcontainers. You do an awesome job!

Same goes to the whole Keycloak team!

Kudos to @thomasdarimont for some inspiration for this project.

License

Apache License 2.0

Copyright (c) 2019-2026 Niko Köbler

See LICENSE file for details.

About

A Testcontainer implementation for Keycloak IAM & SSO.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Sponsor this project

Contributors

Languages