@NonNull
  public Client authenticate(@NonNull Request request) {

    // https://datatracker.ietf.org/doc/html/rfc7521#section-4.2

    try {
      if (!CLIENT_ASSERTION_TYPE_PRIVATE_KEY_JWT.equals(request.clientAssertionType())) {
        throw new AuthenticationException(
            "unsupported client_assertion_type='%s', expected '%s'"
                .formatted(request.clientAssertionType(), CLIENT_ASSERTION_TYPE_PRIVATE_KEY_JWT));
      }

      var processor = new DefaultJWTProcessor<>();

      var keySelector =
          new JWSVerificationKeySelector<>(
              Set.of(JWSAlgorithm.RS256, JWSAlgorithm.ES256), jwkSource);

      processor.setJWSKeySelector(keySelector);

      processor.setJWTClaimsSetVerifier(
          new DefaultJWTClaimsVerifier<>(
              new JWTClaimsSet.Builder().audience(baseUri.toString()).build(),
              Set.of(
                  JWTClaimNames.JWT_ID,
                  JWTClaimNames.EXPIRATION_TIME,
                  JWTClaimNames.ISSUER,
                  JWTClaimNames.SUBJECT)));

      var claims = processor.process(request.clientAssertion(), null);

      var clientId = clientIdFromAssertion(request.clientId(), claims);

      return new Client(clientId);

    } catch (ParseException e) {
      throw new AuthenticationException("failed to parse client assertion", e);
    } catch (BadJOSEException | JOSEException e) {
      throw new AuthenticationException("failed to verify client assertion", e);
    }
  }
@Test
  void authenticate_badAudience() throws JOSEException {

    var key = generateKey();
    var jwkSource = new StaticJwkSource<>(key);

    var claims =
        new JWTClaimsSet.Builder()
            .audience("https://bad-audience.example.com")
            .subject("not the right client")
            .issuer(CLIENT_ID)
            .expirationTime(Date.from(Instant.now().plusSeconds(60)))
            .build();

    var signed = signJwt(claims, key);

    var authenticator = new ClientAuthenticator(jwkSource, RP_ISSUER);

    // when & then
    assertThrows(
        AuthenticationException.class,
        () ->
            authenticator.authenticate(
                new Request(
                    CLIENT_ID, ClientAuthenticator.CLIENT_ASSERTION_TYPE_PRIVATE_KEY_JWT, signed)));
  }