mock-oauth2-server

repository·master·Indexed 19 days ago

https://github.com/navikt/mock-oauth2-server

A scriptable OAuth2/OpenID Connect server for JVM tests and Docker Compose environments. It issues verifiable, signed JWTs to test security-sensitive applications without a real identity provider. Supports multi-issuer setups, major OAuth2 grant types (Authorization Code, Client Credentials, JWT Bearer, Token Exchange, Refresh Token, and Resource Owner Password Credentials), and can be embedded in JVM tests or run as a standalone Docker container.

Tokens
9.1K
Snippets
30
Records
40
Agent score
64%

What's inside mock-oauth2-server

  1. Overview of mock-oauth2-server capabilities

    master

    The mock-oauth2-server is a scriptable OAuth2/OpenID Connect server designed for testing applications that depend on real OIDC providers. It issues signed JWTs that are verifiable via standard JWKS and discovery endpoints, allowing you to test security flows without disabling security in your application.

    Key Features:

    • Supports multi-issuer setups (the first path segment in the URL determines the issuer).
    • Supports all major OAuth2 grant types.
    • Allows token customization.
    • Can be embedded in JVM tests or run as a standalone Docker container.
    WARNING

    This server is for testing only. Do not use it in production.

  2. Supported OAuth2 and OpenID Connect flows

    master

    The server supports the following grant types and flows:

    • OpenID Connect Authorization Code Flow
    • OAuth2 Client Credentials Grant
    • OAuth2 JWT Bearer Grant (On-Behalf-Of flow)
    • OAuth2 Token Exchange Grant
    • OAuth2 Refresh Token Grant
    • OAuth2 Resource Owner Password Credentials Grant (Note: This grant is considered insecure and is being removed from OAuth 2.1)
  3. Migrate to 6.0.0: Debugger behavior changes

    master

    In version 6.0.0, the debugger can no longer be used as a generic OAuth2 client against external identity providers. Previously, the debugger allowed client-supplied URLs via cookies, which posed a security risk.

    New Behavior: The token_url, authorize_url, redirect_uri, client_secret, and client_auth_method are now controlled by the server. In the debugger UI, the endpoint and redirect_uri fields are read-only.

    Migration:

    • If you were using the debugger to test against a third-party provider, point a real OAuth2 client at that provider instead.
    • If you are manually constructing a DebuggerRequestHandler, note that it now requires an OAuth2HttpServer instead of an Ssl? object.
  4. Run MockOAuth2Server via Docker

    master

    The standalone server defaults to port 8080. You can run it using Docker with specific version tags.

    Run with Docker

    docker run -p 8080:8080 ghcr.io/navikt/mock-oauth2-server:$MOCK_OAUTH2_SERVER_VERSION

    Tagging strategy

    • ghcr.io/navikt/mock-oauth2-server:3.1.4: exact version
    • ghcr.io/navikt/mock-oauth2-server:3.1: latest 3.1.x
    • ghcr.io/navikt/mock-oauth2-server:3: latest 3.x.x

    Health check

    GET /isalive returns 200 when the server is ready.

    Windows Note

    On Windows, specify the host explicitly: docker run -p 8080:8080 -h localhost $IMAGE_NAME

    docker run -p 8080:8080 ghcr.io/navikt/mock-oauth2-server:6.0.0
  5. Configure HTTPS for the Mock Server

    master

    You can enable HTTPS in unit tests or via JSON_CONFIG for standalone/Docker deployments.

    In Unit Tests (Kotlin)

    Generate a temporary keystore automatically:

    val ssl = Ssl()
    val server = MockOAuth2Server(
        OAuth2Config(httpServer = MockWebServerWrapper(ssl))
    )

    Or provide your own keystore:

    val ssl = Ssl(
        Sslkeystore(
            keyPassword = "",
            keystoreFile = File("src/test/resources/localhost.p12"),
            keystorePassword = "",
            keystoreType = Sslkeystore.KeyStoreType.PKCS12
        )
    )
    val server = MockOAuth2Server(OAuth2Config(httpServer = MockWebServerWrapper(ssl)))

    Tip: Add ssl.sslKeystore.keyStore to your client's truststore to trust the generated certificate.

    In Docker / Standalone (JSON_CONFIG)

    To generate a keystore automatically:

    {
      "httpServer": {
        "type": "NettyWrapper",
        "ssl": {}
      }
    }

    To use your own keystore:

    {
      "httpServer": {
        "type": "NettyWrapper",
        "ssl": {
            "keyPassword": "",
            "keystoreFile": "src/test/resources/localhost.p12",
            "keystoreType": "PKCS12",
            "keystorePassword": ""
        }
      }
    }
  6. Install mock-oauth2-server via Gradle or Maven

    master

    Add the mock-oauth2-server dependency to your project. Use the testImplementation scope for Gradle or test scope for Maven to ensure it is only available during testing.

    // Gradle Kotlin DSL
    testImplementation("no.nav.security:mock-oauth2-server:$mockOAuth2ServerVersion")
    <!-- Maven -->
    <dependency>
      <groupId>no.nav.security</groupId>
      <artifactId>mock-oauth2-server</artifactId>
      <version>${mock-oauth2-server.version}</version>
      <scope>test</scope>
    </dependency>
  7. Migrate to 5.0.0: Claim precedence in Interactive Login

    master

    In version 5.0.0, a change was made to how claims are prioritized when using interactiveLogin: true alongside requestMappings.

    New Behavior: Claims defined in a matching requestMapping now take precedence over claims submitted via the interactive login page. Login-page claims can add new claims, but they can no longer overwrite existing claims (such as sub) set by a mapping.

    Migration:

    • To override a claim, move that claim into the requestMappings configuration.
    • Alternatively, remove the conflicting key from the requestMapping if you want the login-page value to be used.
  8. Use MockOAuth2Server in JVM Tests

    master

    You can integrate the mock server directly into your Kotlin/Java tests. Use MockOAuth2Server() for manual lifecycle management or withMockOAuth2Server for automatic start/shutdown.

    Minimal Setup

    val server = MockOAuth2Server()
    server.start()
    
    val wellKnownUrl = server.wellKnownUrl("default").toString()
    // configure your app to use wellKnownUrl, run your test, then:
    
    server.shutdown()

    Automatic Lifecycle

    withMockOAuth2Server {
        val wellKnownUrl = wellKnownUrl("default").toString()
        // configure your app and run your test here
    }
  9. Configure Docker Compose networking

    master

    When running alongside your application in Docker Compose, choose the scenario that fits your testing needs:

    Scenario 1: Container-to-container only

    Use this for standard integration tests where services communicate over the internal Docker network. Your app should use the mock server's service name as the hostname.

    Scenario 2: Container-to-container + browser interaction

    Use this if a browser (e.g., for Authorization Code Flow) also needs to reach the mock server.

    1. Add 127.0.0.1 host.docker.internal to your /etc/hosts (Linux only; macOS/Windows handled automatically).
    2. Set hostname: host.docker.internal on the mock server service.
    3. Use host.docker.internal in your application's environment variables.
    NOTE

    Each service must use a different host port to avoid port is already allocated errors.

    services:
      your_app:
        build: .
        ports:
          - 8080:8080
        environment:
          - SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI=http://host.docker.internal:8090/default/jwks
      mock-oauth2-server:
        image: ghcr.io/navikt/mock-oauth2-server:6.0.0
        ports:
          - 8090:8080
        hostname: host.docker.internal
  10. Quick Start: Use mock-oauth2-server in JVM tests

    master

    To use the mock server within your JVM-based tests, add the dependency to your build tool and use the MockOAuth2Server class to manage the server lifecycle and issue tokens. The server provides a discovery URL that your application can use to configure its OIDC client.

    val server = MockOAuth2Server()
    server.start()
    
    val token = server.issueToken(
        issuerId = "default",
        subject = "user123",
        audience = "my-api",
    )
    
    // Point your app at the discovery URL
    val wellKnownUrl = server.wellKnownUrl("default").toString()
    
    // Attach the token to a request
    request.addHeader("Authorization", "Bearer ${token.serialize()}")
    
    server.shutdown()
  11. Run mock-oauth2-server as a standalone Docker container

    master

    You can run the server as a standalone process using Docker. By default, it listens on port 8080. The issuer ID is determined by the first path segment of the URL.

    ```bash
    docker run -p 8080:8080 ghcr.io/navikt/mock-oauth2-server:$MOCK_OAUTH2_SERVER_VERSION

    Default Endpoints (for issuer default):

    • Token endpoint: http://localhost:8080/default/token
    • Discovery: http://localhost:8080/default/.well-known/openid-configuration
  12. Migrate to 6.0.0: Handle missing logback-classic and kotlinx-serialization-json

    master

    In version 6.0.0, logback-classic and kotlinx-serialization-json are no longer bundled in the published POM to prevent classpath pollution. They are now restricted to test and standalone-only scopes.

    If your test logs are missing or you were relying on transitive access to kotlinx-serialization-json, you must declare them explicitly in your dependencies.

    Note: The standalone server and Docker image still include logback automatically.

    // If test logs are missing, add a binding explicitly
    testRuntimeOnly("ch.qos.logback:logback-classic:<version>")
    
    // If you used kotlinx-serialization-json without declaring it, add it explicitly
    dependency("org.jetbrains.kotlinx:kotlinx-serialization-json:<version>")