public TokenResponse exchangePkceCode(
      URI tokenEndpoint, String code, String redirectUri, String clientId, String codeVerifier) {

    var body =
        UrlFormBodyBuilder.create()
            .param("grant_type", "authorization_code")
            .param("redirect_uri", redirectUri)
            .param("client_id", clientId)
            .param("code", code)
            .param("code_verifier", codeVerifier)
            .build();

    var headers =
        List.of(
            new Header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON),
            new Header(HttpHeaders.CONTENT_TYPE, UrlFormBodyBuilder.MEDIA_TYPE));

    var req = new Request(tokenEndpoint, "POST", headers, body);

    var res = httpClient.call(req);
    if (res.status() != 200) {
      throw HttpExceptions.httpFailBadStatus(req.method(), tokenEndpoint, res.status());
    }

    return JsonCodec.readValue(res.body(), TokenResponse.class);
  }
@Test
  void exchangePkceCode(WireMockRuntimeInfo wm) {

    var body =
        """
        {
          "access_token" : null,
          "token_type"   : "Bearer",
          "expires_in"   : 3600,
          "id_token"     : "eyJraWQiOiIxZTlnZGs3IiwiYWxnIjoiUl..."
        }
        """
            .getBytes(StandardCharsets.UTF_8);

    var path = "/auth/token";
    stubFor(post(path).willReturn(ok().withBody(body)));

    var base = URI.create(wm.getHttpBaseUrl());

    var code = "s3cret";
    var codeVerifier = "k3k3k";
    var clientId = "myclient";
    var redirectUri = "http://localhost:8080/callback";

    var res =
        client.exchangePkceCode(base.resolve(path), code, redirectUri, clientId, codeVerifier);

    assertEquals("Bearer", res.tokenType());
    assertEquals(3600, res.expiresIn());
    assertThat(res.idToken(), not(emptyOrNullString()));
  }