@Override
    public Mono<Authentication> convert(ServerWebExchange exchange) {
        return super.convert(exchange)
            // validate the password
            .<Authentication>flatMap(token -> {
                var credentials = (String) token.getCredentials();
                byte[] credentialsBytes;
                try {
                    credentialsBytes = Base64.getDecoder().decode(credentials);
                } catch (IllegalArgumentException e) {
                    // the credentials are not in valid Base64 scheme
                    return Mono.error(new BadCredentialsException("Invalid Base64 scheme."));
                }
                return cryptoService.decrypt(credentialsBytes)
                    .onErrorMap(InvalidEncryptedMessageException.class,
                        error -> new BadCredentialsException("Invalid credential.", error))
                    .map(decryptedCredentials -> new UsernamePasswordAuthenticationToken(
                        token.getPrincipal(),
                        new String(decryptedCredentials, UTF_8)));
            })
            .transformDeferred(createIpBasedRateLimiter(exchange))
            .onErrorMap(RequestNotPermitted.class, RateLimitExceededException::new);
    }
@Test
    void applyUsernameAndInvalidPasswordThenBadCredentialsException() {
        var username = "username";
        var password = "password";

        formData.add("username", username);
        formData.add("password", Base64.getEncoder().encodeToString(password.getBytes()));

        when(cryptoService.decrypt(password.getBytes()))
            .thenReturn(Mono.error(() -> new InvalidEncryptedMessageException("invalid message")));
        StepVerifier.create(converter.convert(exchange))
            .verifyError(BadCredentialsException.class);
        verify(cryptoService).decrypt(password.getBytes());
    }