@Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(final ServerCall<ReqT, RespT> call,
            final Metadata headers, final ServerCallHandler<ReqT, RespT> next) {
        Authentication authentication;
        try {
            authentication = this.grpcAuthenticationReader.readAuthentication(call, headers);
        } catch (final AuthenticationException e) {
            log.debug("Failed to read authentication: {}", e.getMessage());
            throw e;
        }
        if (authentication == null) {
            log.debug("No credentials found: Continuing unauthenticated");
            try {
                return next.startCall(call, headers);
            } catch (final AccessDeniedException e) {
                throw newNoCredentialsException(e);
            }
        }
        if (authentication.getDetails() == null && authentication instanceof AbstractAuthenticationToken) {
            // Append call attributes to the authentication request.
            // This gives the AuthenticationManager access to information like remote and local address.
            // It can then decide whether it wants to use its own user details or the attributes.
            ((AbstractAuthenticationToken) authentication).setDetails(call.getAttributes());
        }
        log.debug("Credentials found: Authenticating '{}'", authentication.getName());
        try {
            authentication = this.authenticationManager.authenticate(authentication);
        } catch (final AuthenticationException e) {
            log.debug("Authentication request failed: {}", e.getMessage());
            onUnsuccessfulAuthentication(call, headers, e);
            throw e;
        }

        final SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
        securityContext.setAuthentication(authentication);
        SecurityContextHolder.setContext(securityContext);
        @SuppressWarnings("deprecation")
        final Context grpcContext = Context.current().withValues(
                SECURITY_CONTEXT_KEY, securityContext,
                AUTHENTICATION_CONTEXT_KEY, authentication);
        final Context previousContext = grpcContext.attach();
        log.debug("Authentication successful: Continuing as {} ({})", authentication.getName(),
                authentication.getAuthorities());
        onSuccessfulAuthentication(call, headers, authentication);
        try {
            return new AuthenticatingServerCallListener<>(next.startCall(call, headers), grpcContext, securityContext);
        } catch (final AccessDeniedException e) {
            if (authentication instanceof AnonymousAuthenticationToken) {
                throw newNoCredentialsException(e);
            } else {
                throw e;
            }
        } finally {
            SecurityContextHolder.clearContext();
            grpcContext.detach(previousContext);
            log.debug("startCall - Authentication cleared");
        }
    }
Creates a new DefaultAuthenticatingServerInterceptor with the given authentication manager and reader.

@param authenticationManager The authentication manager used to verify the credentials.
@param authenticationReader The authentication reader used to extract the credentials from the call.
grpc-server-spring-boot-starter/src/main/java/net/devh/boot/grpc/server/security/interceptors/DefaultAuthenticatingServerInterceptor.java