This version is still in development and is not considered stable yet. For the latest stable version, please use Spring gRPC 1.0.3!

GRPC Server

This section describes core concepts that Spring gRPC uses on the server side. We recommend reading it closely to understand the ideas behind how Spring gRPC is implemented. You only need to provide one or more beans of type BindableService to create a gRPC server, provided the classpath contains an implementation of a Server. The BindableService is a gRPC service that can be bound to a server. The Server is the gRPC server that listens for incoming requests and routes them to the appropriate service implementation.

Create a gRPC Service

To create a gRPC server, you need to provide a GrpcServerFactory one or more beans of type BindableService. There are some BindableServices available off the shelf that you could include in your application (e.g. the gRPC Reflection or gRPC Health services). Very commonly, you will create your own BindableService by extending the generated service implementation from your Protobuf file. The easiest way to activate it is to simply add a Spring @Service annotation to the implementation class and have it picked up by the @ComponentScan in your Spring Boot application.

Service Filtering

All available BindableService beans are bound to all running gRPC servers. However, you can register a ServerServiceDefinitionFilter bean to decide which services are bound to which server factories.

The following example prevents the "health" and "reflection" service from being bound to the server created by the server factory that the filter is applied to (e.g. the InProcessGrpcServerFactory).

@Bean
ServerServiceDefinitionFilter myServiceFilter() {
    return (serviceDefinition, __) ->
            !Set.of(HealthGrpc.SERVICE_NAME, ServerReflectionGrpc.SERVICE_NAME)
                    .contains(serviceDefinition.getServiceDescriptor().getName());
}

The InProcessGrpcServerFactory picks up the ServerServiceDefinitionFilter automatically. Any other server factory will require you to provide a GrpcServerFactoryCustomizer in which you can modify the factory by adding a filter, as shown in the following example:

@Bean
GrpcServerFactoryCustomizer myServerFactoryCustomizer(ServerServiceDefinitionFilter myServiceFilter) {
    return factory -> {
        if (factory instanceof NettyGrpcServerFactory nettyServerFactory) {
            nettyServerFactory.setServiceFilter(myServiceFilter);
        }
    };
}

Netty Server

If you use the NettyGrpcServerFactory, the server will be a Netty-based implementation. You can configure common features of the server by using a ServerBuilderCustomizer bean to customize the ServerBuilder before it is used to create the server.

Shaded Netty

You can switch to a shaded Netty provided by the gRPC team by adding the grpc-netty-shaded dependency and creating a ShadedNettyGrpcServerFactory bean in your application context.

Servlet Server

Any servlet container can be used to run a gRPC server.

To run in this mode you must enable HTTP2 on the server by setting the container up using its own infrastructure. Spring Boot provides auto-configuration for Tomcat and Jetty, and you can use the usual configuration properties to enable HTTP2. The servlet that is created is mapped to process HTTP POST requests to the paths defined by the registered services, as /<service-name>/*. Clients can connect to the server using that path, which is what any gRPC client library will do.

The gRPC server has fewer configuration options when running in a servlet container, as the servlet container is responsible for the network layer. You can still add ServerBuilderCustomizer beans to customize the server as it is built, but some features common in the "native" builders are not available and may throw exceptions at runtime.

Native gRPC Server inside a Servlet Container

The native gRPC server (with netty etc.) will run happily inside a web application, listening on a different port.

InProcess Server

You can run an in-process server (i.e. not listening on a network port) by including the io.grpc.grpc-inprocess dependency on your classpath and using the InProcessGrpcServerFactory. This is useful for testing, but it can also be used in production if you want to run a gRPC server that is only accessible from within the same application (e.g. for internal communication between different modules of the same application).

In this mode, the in-process server factory is auto-configured in addition to the regular server factory (e.g. Netty).

To use the inprocess server the channel target must be set to in-process:<in-process-name>

Server Interceptors

Global

To add a server interceptor to be applied to all services you can simply register a server interceptor bean and then annotate it with @GlobalServerInterceptor. The interceptors are ordered according to their bean natural ordering (i.e. @Order).

@Bean
@Order(100)
@GlobalServerInterceptor
ServerInterceptor myGlobalLoggingInterceptor() {
    return new MyLoggingInterceptor();
}

Filtering

All global interceptors are applied to all created services by default. However, you can register a ServerInterceptorFilter bean to decide which interceptors are applied to which server factories.

The following example prevents the ExtraThingsInterceptor interceptor from being applied to any servers created by the server factory that the filter is applied to.

@Bean
ServerInterceptorFilter myInterceptorFilter() {
	return (interceptor, service) ->
			!(interceptor instanceof ExtraThingsInterceptor);
}

You will need to provide a GrpcServerFactoryCustomizer in which you can modify the factory by adding a filter, as shown in the following example:

@Bean
GrpcServerFactoryCustomizer myServerFactoryCustomizer() {
	return factory -> {
		if (factory instanceof NettyGrpcServerFactory) {
			((DefaultGrpcServerFactory)factory).setInterceptorFilter(myInterceptorFilter());
		}
	};
}

Per-Service

To add a server interceptor to be applied to a single service you can simply register a server interceptor bean and then annotate your BindableService bean with @GrpcService, specifying the interceptor using either the interceptors or interceptorNames attribute.

The interceptors are ordered according to their position in the attribute list. When using both interceptors and interceptorNames, the former entries precede the latter.

In the following example, the myServerInterceptor will be applied to the myService service.

@Bean
MyServerInterceptor myServerInterceptor() {
    return new MyServerInterceptor();
}

@GrpcService(interceptors = MyServerInterceptor.class)
BindableService myService() {
	...
}

When a service is configured with both global and per-service interceptors, the global interceptors are first applied in their sorted order followed by the per-service interceptors in their sorted order.

However, by setting the blendWithGlobalInterceptors attribute on the @GrpcService annotation to "true" you can change this behavior so that the interceptors are all combined and then sorted according to their bean natural ordering (i.e. @Order).

You can use this option if you want to add a per-service interceptor between global interceptors.

Reflection

Spring gRPC allows you to create an instance of the standard gRPC Reflection service which enables clients to browse the metadata of your services and download the Protobuf files.

The reflection service resides in the io.grpc:grpc-services library which is marked as optional by Spring gRPC. You must add this dependency to your application in order for it to be autoconfigured.

Health

Spring gRPC autoconfigures the standard gRPC Health service for performing health check calls against gRPC servers. The health service is registered with the gRPC server and a HealthStatusManager bean is provided that can be used to update the health status of your services.

The health service resides in the io.grpc:grpc-services library which is marked as optional by Spring gRPC. You must add this dependency to your application in order for it to be autoconfigured.
Server-side gRPC health is enabled by default when the application defines at least one BindableService. If no server-side gRPC services are present, health is disabled by default and must be explicitly enabled using spring.grpc.server.health.enabled=true.

Observability

Observability features are provided by Micrometer. Spring Boot has some auto-configuration for Micrometer, and Spring gRPC provides some additional auto-configuration to add gRPC-specific metrics.

Exception Handling

Spring gRPC provides an autoconfigured exception handler that can be used to provide a consistent way to handle exceptions in your gRPC services. All you need to do is add @Beans of type GrpcExceptionHandler to your application context, and they will be used to handle exceptions thrown by your services. A GrpcExceptionHandler can be used to handle exceptions of a specific type, returning null for those it does not support, or to handle all exceptions.

Testing

If you include spring-grpc-test in your project, your gRPC server in a @SpringBootTest can be started in-process (i.e. not listening on a network port) by enabling the in-process server. All clients that connect to any server via the autoconfigured GrpcChannelFactory will be able to connect to it.

Security

Netty

The netty-based server supports TLS and mTLS out of the box. To enable it, you need to add the appropriate KeyManager and/or TrustManager to the server configuration. You can do this by creating a ServerBuilderCustomizer or in the @Bean definition for the NettyGrpcServerFactory itself.

Declarative Security with Spring Security

If you want to enhance the security of your gRPC server, you can use Spring Security by employing similar mechanisms to those used for regular HTTP security. Enable Spring Security as normal, and ensure that there is an AuthenticationManager bean in the context. Then create a AuthenticationProcessInterceptor bean that uses the AuthenticationManager to authenticate requests, and add it as a global server interceptor (see above). You can then use @Preauthorize on your BindableService beans to enforce authorization rules with roles (more precisely authorities in Spring Security terminology).

This pattern will be familiar to anyone who has used Spring Security before. Here’s an example:

@Bean
@GlobalServerInterceptor
AuthenticationProcessInterceptor jwtSecurityFilterChain(GrpcSecurity grpc) throws Exception {
	return grpc
			.authorizeRequests(requests -> requests
					.methods("Simple/StreamHello").hasAuthority("ROLE_ADMIN")
					.methods("Simple/SayHello").hasAuthority("ROLE_USER")
					.methods("grpc.*/*").permitAll()
					.allRequests().denyAll())
			.httpBasic(withDefaults())
			.preauth(withDefaults())
			.build();
}

Here we configure a filter that allows access to one method only to admin users, and another to users with the "USER" role; access to all gRPC services (e.g. reflection and health indicators) is allowed to all; and all other requests are denied. We also enable HTTP Basic authentication and preauthentication (mTLS) (withDefaults() is a static import from the Customizer in Spring Security).

OAuth2 Resource Server

Similar to the way Spring Boot works with normal web applications, if you have the spring-security-oauth2-resource-server dependency on the classpath, Spring gRPC will be able to configure an OAuth2 resource server through the GrpcSecurity configurer.

Servlet

The servlet-based server supports any security configuration that the servlet container supports, including Spring Security. This means that you can easily implement your favourite authentication and authorization mechanisms. The server will reject unauthenticated requests with a 401 status code and unauthenticated requests with an invalid token with a 403 status code, as with a normal HTTP API. It will also send an appropriate WWW-Authenticate header, e.g. with the value Bearer to indicate that it is expecting a token (for example). The gRPC response will also contain a Status with the appropriate error code and message. For authorization checking, e.g. role-based access control, your BindableService beans can be annotated with @PreAuthorize.

N.B. if you customize the gRPC server call executors, you will need to ensure that you wrap them in a DelegatingSecurityContextExecutor (from Spring Security).

Here’s an example with HTTP Basic authentication:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
	return http.httpBasic(Customizer.withDefaults())
		.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated())
		.csrf((csrf) -> csrf.disable())
		.build();
}

By default, CSRF protection should be disabled for gRPC requests because it is incompatible with the protocol.

Securing Individual Methods

Individual gRPC methods can be secured by adding @PreAuthorize to the method definition. Or you can use the knowledge that the HTTP endpoint is <service>/<method> to configure the security using the usual HttpSecurity configuration. Example:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
	return http.authorizeHttpRequests((requests) -> requests
		.requestMatchers("/Simple/SayHello").hasRole("USER")
		.requestMatchers("/Simple/StreamHello").hasRole("ADMIN")
		.requestMatchers("/grpc.*/*").permitAll()
		.anyRequest().authenticated())
		.build();
}

Here we allow access to the Simple/SayHello method to users with the USER role, and to the Simple/StreamHello method to users with the ADMIN role, and allow access to all gRPC-provided services (like reflection and health indicators), while disallowing access to all other methods unless authenticated.