@POST
  @Path("/token")
  @Produces(MediaType.APPLICATION_JSON)
  public Response token(
      @FormParam("code") String code,
      @FormParam("grant_type") String grantType,
      @FormParam("redirect_uri") String redirectUri,
      @FormParam("client_id") String clientId,
      @FormParam("client_assertion_type") String clientAssertionType,
      @FormParam("client_assertion") String clientAssertion) {

    if (!"authorization_code".equals(grantType)) {
      return Response.status(Status.BAD_REQUEST).entity("bad 'grant_type': " + grantType).build();
    }

    var authenticatedClient =
        authenticator.authenticate(new Request(clientId, clientAssertionType, clientAssertion));

    var redeemed = tokenIssuer.redeem(code, redirectUri, authenticatedClient.clientId());
    if (redeemed == null) {
      return Response.status(Status.BAD_REQUEST).entity("invalid code").build();
    }

    var cacheControl = new CacheControl();
    cacheControl.setNoStore(true);

    return Response.ok(
            new TokenResponse(
                redeemed.accessToken(),
                "Bearer",
                null,
                (int) redeemed.expiresInSeconds(),
                redeemed.idToken()))
        .cacheControl(cacheControl)
        .build();
  }
@Test
  void token() {

    var tokenIssuer = mock(TokenIssuer.class);
    var authenticator = mock(ClientAuthenticator.class);

    var sut = new TokenEndpoint(tokenIssuer, authenticator);

    var clientId = "myapp";

    var grantType = "authorization_code";

    var idToken = UUID.randomUUID().toString();
    var accessToken = UUID.randomUUID().toString();
    var expiresIn = 3600;

    var code = "6238e4504332468aa0c12e300787fded";
    var token = new Token(accessToken, idToken, expiresIn);
    when(tokenIssuer.redeem(code, REDIRECT_URI.toString(), clientId)).thenReturn(token);
    when(authenticator.authenticate(any())).thenReturn(new Client(clientId));

    // when
    try (var res = sut.token(code, grantType, REDIRECT_URI.toString(), clientId, null, null)) {

      // then
      assertEquals(Status.OK.getStatusCode(), res.getStatus());
      var got = res.readEntity(TokenResponse.class);

      assertEquals(idToken, got.idToken());
      assertEquals(accessToken, got.accessToken());
      assertEquals(expiresIn, got.expiresIn());
    }
  }