class AuthenticationInterceptor implements ServerInterceptor {

    @Override
    public <T, R> ServerCall.Listener<T> interceptCall(ServerCall<T, R> serverCall, Metadata metadata, ServerCallHandler<T, R> serverCallHandler) {
        String token = metadata.get(GrpcMetadataKeys.TOKEN_KEY);
        StatusRuntimeException sre = null;
        String context = GrpcMetadataKeys.CONTEXT_KEY.get();

        if( token == null) {
            token = metadata.get(GrpcMetadataKeys.AXONDB_TOKEN_KEY);
        }
        if( context == null) {
            context = metadata.get(GrpcMetadataKeys.AXONDB_CONTEXT_MD_KEY);
        }

        if (token == null) {
            sre = GrpcExceptionBuilder.build(ErrorCode.AUTHENTICATION_TOKEN_MISSING,
                                             "No token for " + serverCall.getMethodDescriptor().getFullMethodName());
        } else if (!axonServerAccessController.allowed(serverCall.getMethodDescriptor().getFullMethodName(),
                                                       context,
                                                       token)) {
            sre = GrpcExceptionBuilder.build(ErrorCode.AUTHENTICATION_INVALID_TOKEN, "Invalid token for " + serverCall.getMethodDescriptor().getFullMethodName());
        }

        if( sre != null) {
            serverCall.close(sre.getStatus(), sre.getTrailers());
            return new ServerCall.Listener<T>() {};
        }

        Context updatedGrpcContext = Context.current().withValue(GrpcMetadataKeys.TOKEN_CONTEXT_KEY, token);
        return Contexts.interceptCall(updatedGrpcContext, serverCall, metadata, serverCallHandler);
    }

    public  AuthenticationInterceptor(AxonServerAccessController axonServerAccessController);

}