Java Library

Embedding Fake ID directly in a Java project

Why embed Fake ID?

Running Fake ID in Docker is the common case, but sometimes you want an OIDC provider living inside a JVM test — no container runtime, no port collisions, no image pulls. Fake ID is published to Maven Central and exposes the same configuration model as the Docker image.

Pick a flavour

Fake ID ships as two artifacts. Pick based on whether your test needs to talk HTTP or not.

ArtifactPulls inUse when
fakeid-coreCore OIDC logic. No Javalin, no Jetty, no HTTP server.Unit tests that want to mint or verify tokens entirely in-process.
fakeidCore + Javalin HTTP adapter.Integration tests where a relying party hits /authorize, /token, /jwks etc. over the network.

If you’re unsure, start with fakeid-core — it’s smaller, faster to set up, and you can graduate to fakeid if you need an actual HTTP endpoint.

fakeid-core — Javalin-free

Maven

<dependency>
    <groupId>com.elevenware</groupId>
    <artifactId>fakeid-core</artifactId>
    <version>0.1.0</version>
</dependency>

Gradle

implementation 'com.elevenware:fakeid-core:0.1.0'

Usage

The entry point is FakeIdCore, constructed from a Configuration. It exposes the same endpoints the HTTP server routes to — authorize, token, discovery, jwks, userInfo, introspect — as plain method calls.

FakeIdCore core = new FakeIdCore(Configuration.builder().build());

AuthorizeResponse auth = core.authorize(new AuthorizeRequest(
        "my-client", "https://app/cb", "code",
        Set.of("openid"), "state-abc", "nonce-xyz"));

TokenResponse tokens = core.token(new TokenRequest(
        "authorization_code", auth.code(), null, "my-client", "ignored"));

// tokens.idToken() is a signed JWT you can parse and assert on.

To verify the signature in a test, pass your own signing key in via Configuration. Both RSA and EC keys are supported:

RSA (RS256, RS384, RS512, PS256, PS384, PS512):

RSAKey jwk = new RSAKeyGenerator(2048)
        .keyUse(KeyUse.SIGNATURE)
        .keyID("signingKey")
        .algorithm(JWSAlgorithm.RS256)
        .generate();

FakeIdCore core = new FakeIdCore(Configuration.builder()
        .jwks(new JWKSet(jwk))
        .claims(Map.of("sub", "alice@example.com"))
        .build());

TokenResponse tokens = /* ... as above ... */;
SignedJWT idToken = SignedJWT.parse(tokens.idToken());
idToken.verify(new RSASSAVerifier(jwk));

EC (ES256, ES384, ES512):

ECKey ecJwk = new ECKeyGenerator(Curve.P_256)
        .keyUse(KeyUse.SIGNATURE)
        .keyID("signingKey")
        .algorithm(JWSAlgorithm.ES256)
        .generate();

FakeIdCore core = new FakeIdCore(Configuration.builder()
        .jwks(new JWKSet(ecJwk))
        .claims(Map.of("sub", "alice@example.com"))
        .build());

TokenResponse tokens = /* ... as above ... */;
SignedJWT idToken = SignedJWT.parse(tokens.idToken());
idToken.verify(new ECDSAVerifier(ecJwk));

Alternatively, let Fake ID generate an EC key automatically by specifying the algorithm:

FakeIdCore core = new FakeIdCore(Configuration.builder()
        .signingAlgorithm(JWSAlgorithm.ES256)
        .claims(Map.of("sub", "alice@example.com"))
        .build());

fakeid — full OIDC server

Maven

<dependency>
    <groupId>com.elevenware</groupId>
    <artifactId>fakeid</artifactId>
    <version>0.1.0</version>
</dependency>

Gradle

implementation 'com.elevenware:fakeid:0.1.0'

Usage

The entry point is FakeIdApplication, which takes a Configuration and exposes start(), stop(), and port(). There are three ways to build the Configuration:

The three approaches share the same underlying configuration model, but the builder does not map 1:1 to every environment-variable format — for example, FAKEID_SIGNING_KEY is a base64-encoded PEM that gets parsed into a JWKSet, whereas the builder’s jwks(...) method takes a JWKSet directly.

Minimal

Configuration configuration = Configuration.builder()
        .port(8091)
        .build();

FakeIdApplication app = new FakeIdApplication(configuration).start();

// ... your relying party points at http://localhost:8091 ...

app.stop();

Ephemeral port for tests

To bind to a free port, use randomPort() (or .port(0)). Read the actual port back from the started application, and stop the application in a finally block so a failing assertion doesn’t leak a running server:

FakeIdApplication app = new FakeIdApplication(
        Configuration.builder()
                .randomPort()
                .build())
        .start();

try {
    int port = app.port();
    String issuer = "http://localhost:" + port;
    // ... exercise your relying party against `issuer` ...
} finally {
    app.stop();
}

Fully configured

Supply your own signing key and override the claims returned in id tokens. Providing a key you persist and reuse across startups keeps the JWKS stable — generating a fresh key on every start (as shown below) produces a different JWKS each run, which can cause signature-verification errors in relying parties that cache the JWKS.

RSA key:

RSAKey jwk = new RSAKeyGenerator(2048)
        .keyUse(KeyUse.SIGNATURE)
        .keyID("signingKey")
        .algorithm(JWSAlgorithm.RS256)
        .generate();

Configuration configuration = Configuration.builder()
        .port(8091)
        .jwks(new JWKSet(jwk))
        .claims(Map.of(
                "sub", "jeff@example.com",
                "additionalClaims", Map.of("claim", "claimValue")))
        .build();

FakeIdApplication app = new FakeIdApplication(configuration).start();

EC key (ES256/ES384/ES512):

ECKey ecJwk = new ECKeyGenerator(Curve.P_256)
        .keyUse(KeyUse.SIGNATURE)
        .keyID("signingKey")
        .algorithm(JWSAlgorithm.ES256)
        .generate();

Configuration configuration = Configuration.builder()
        .port(8091)
        .jwks(new JWKSet(ecJwk))
        .claims(Map.of("sub", "jeff@example.com"))
        .build();

FakeIdApplication app = new FakeIdApplication(configuration).start();

Using it in a JUnit 5 test

A typical pattern is to start Fake ID (either flavour) once per test class. With fakeid:

class MyOidcIntegrationTest {

    private static FakeIdApplication fakeId;
    private static String issuer;

    @BeforeAll
    static void startFakeId() {
        fakeId = new FakeIdApplication(
                Configuration.builder().randomPort().build())
                .start();
        issuer = "http://localhost:" + fakeId.port();
    }

    @AfterAll
    static void stopFakeId() {
        fakeId.stop();
    }

    @Test
    void discoveryDocumentIsServed() throws Exception {
        HttpResponse<String> response = HttpClient.newHttpClient()
                .send(HttpRequest.newBuilder()
                        .uri(URI.create(issuer + "/.well-known/openid-configuration"))
                        .GET()
                        .build(),
                        HttpResponse.BodyHandlers.ofString());
        assertEquals(200, response.statusCode());
    }
}

With fakeid-core, the same idea but without an HTTP hop:

class MyOidcUnitTest {

    private FakeIdCore core;

    @BeforeEach
    void buildCore() {
        core = new FakeIdCore(Configuration.builder().build());
    }

    @Test
    void tokenMintedForClientCredentials() {
        TokenResponse tokens = core.token(new TokenRequest(
                "client_credentials", null, "api:read", "c1", "s1"));

        assertEquals("Bearer", tokens.tokenType());
        assertNotNull(tokens.accessToken());
    }
}