To implement a gRPC service using the Mutiny API, create a class that implements the service interface.
Then, implement the methods defined in the service interface.
If you don’t want to implement a service method just throw an
java.lang.UnsupportedOperationException
from the method body (the exception will be automatically converted to the appropriate gRPC exception).
Finally, implement the service and add the
@GrpcService
annotation:
import io.quarkus.grpc.GrpcService;
import hello.Greeter;
@GrpcService (1)
public class HelloService implements Greeter { (2)
@Override
public Uni<HelloReply> sayHello(HelloRequest request) {
return Uni.createFrom().item(() ->
HelloReply.newBuilder().setMessage("Hello " + request.getName()).build()
A gRPC service implementation bean must be annotated with the @GrpcService annotation and should not declare any other CDI qualifier. All gRPC services have the jakarta.inject.Singleton scope. Additionally, the request context is always active during a service call.
hello.Greeter is the generated service interface.
To implement a gRPC service using the default gRPC API, create a class that extends the default implementation base.
Then, override the methods defined in the service interface.
Finally, implement the service and add the @GrpcService annotation:
import io.quarkus.grpc.GrpcService;
@GrpcService
public class HelloService extends GreeterGrpc.GreeterImplBase {
@Override
public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
String name = request.getName();
String message = "Hello " + name;
responseObserver.onNext(HelloReply.newBuilder().setMessage(message).build());
responseObserver.onCompleted();
By default, all the methods from a gRPC service run on the event loop.
As a consequence, you must not block.
If your service logic must block, annotate the method with io.smallrye.common.annotation.Blocking:
@Override
@Blocking
public Uni<HelloReply> sayHelloBlocking(HelloRequest request) {
// Do something blocking before returning the Uni
service Streaming {
rpc Source(Empty) returns (stream Item) {} // Returns a stream
rpc Sink(stream Item) returns (Empty) {} // Reads a stream
rpc Pipe(stream Item) returns (stream Item) {} // Reads a streams and return a streams
Using Mutiny, you can implement these as follows:
import io.quarkus.grpc.GrpcService;
@GrpcService
public class StreamingService implements Streaming {
@Override
public Multi<Item> source(Empty request) {
// Just returns a stream emitting an item every 2ms and stopping after 10 items.
return Multi.createFrom().ticks().every(Duration.ofMillis(2))
.select().first(10)
.map(l -> Item.newBuilder().setValue(Long.toString(l)).build());
@Override
public Uni<Empty> sink(Multi<Item> request) {
// Reads the incoming streams, consume all the items.
return request
.map(Item::getValue)
.map(Long::parseLong)
.collect().last()
.map(l -> Empty.newBuilder().build());
@Override
public Multi<Item> pipe(Multi<Item> request) {
// Reads the incoming stream, compute a sum and return the cumulative results
// in the outbound stream.
return request
.map(Item::getValue)
.map(Long::parseLong)
.onItem().scan(() -> 0L, Long::sum)
.onItem().transform(l -> Item.newBuilder().setValue(Long.toString(l)).build());
rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);
Clients can specify the fully qualified service name to get the health status of a specific service
or skip specifying the service name to get the general status of the gRPC server.
For more details, check out the
gRPC documentation
Additionally, if Quarkus SmallRye Health is added to the application, a readiness check for
the state of the gRPC services will be added to the MicroProfile Health endpoint response, that is /q/health.
Quarkus gRPC Server implements the reflection service .
This service allows tools like grpcurl or grpcox to interact with your services.
The reflection service is enabled by default in dev mode.
In test or production mode, you need to enable it explicitly by setting quarkus.grpc.server.enable-reflection-service to true.
Do we use separate HTTP server to serve gRPC requests. Set this to false if you want to use new Vert.x gRPC support, which uses existing Vert.x HTTP server.
Environment variable: QUARKUS_GRPC_SERVER_USE_SEPARATE_SERVER
When using a single server (using quarkus.grpc.server.use-separate-server=false), the default value is 256KB. When using a separate server (using quarkus.grpc.server.use-separate-server=true), the default value is 4MB.
Environment variable: QUARKUS_GRPC_SERVER_MAX_INBOUND_MESSAGE_SIZE
The classpath path or file path to a server certificate or certificate chain in PEM format.
Environment variable: QUARKUS_GRPC_SERVER_SSL_CERTIFICATE
The classpath path or file path to the corresponding certificate private key file in PEM format.
Environment variable: QUARKUS_GRPC_SERVER_SSL_KEY
An optional keystore that holds the certificate information instead of specifying separate files. The keystore can be either on classpath or an external file.
Environment variable: QUARKUS_GRPC_SERVER_SSL_KEY_STORE
An optional parameter to specify the type of the keystore file. If not given, the type is automatically detected based on the file name.
Environment variable: QUARKUS_GRPC_SERVER_SSL_KEY_STORE_TYPE
An optional trust store which holds the certificate information of the certificates to trust
The trust store can be either on classpath or an external file.
Environment variable: QUARKUS_GRPC_SERVER_SSL_TRUST_STORE
An optional parameter to specify type of the trust store file. If not given, the type is automatically detected based on the file name.
Environment variable: QUARKUS_GRPC_SERVER_SSL_TRUST_STORE_TYPE
If not set, it defaults to "TLSv1.3, TLSv1.2". The following list of protocols are supported: TLSv1, TLSv1.1, TLSv1.2, TLSv1.3. To only enable TLSv1.3, set the value to to "TLSv1.3".
Note that setting an empty list, and enabling SSL/TLS is invalid. You must at least have one protocol.
Environment variable: QUARKUS_GRPC_SERVER_SSL_PROTOCOLS
Enables the gRPC Reflection Service. By default, the reflection service is only exposed in dev mode. This setting allows overriding this choice and enable the reflection service every time.
Environment variable: QUARKUS_GRPC_SERVER_ENABLE_REFLECTION_SERVICE
Number of gRPC server verticle instances. This is useful for scaling easily across multiple cores. The number should not exceed the amount of event loops.
Environment variable: QUARKUS_GRPC_SERVER_INSTANCES
Sets a custom keep-alive duration. This configures the time before sending a keepalive ping when there is no read activity.
Environment variable: QUARKUS_GRPC_SERVER_NETTY_KEEP_ALIVE_TIME
Sets a custom permit-keep-alive duration. This configures the most aggressive keep-alive time clients are permitted to configure. The server will try to detect clients exceeding this rate and when detected will forcefully close the connection.
Environment variable: QUARKUS_GRPC_SERVER_NETTY_PERMIT_KEEP_ALIVE_TIME
Sets whether to allow clients to send keep-alive HTTP/2 PINGs even if there are no outstanding RPCs on the connection.
Environment variable: QUARKUS_GRPC_SERVER_NETTY_PERMIT_KEEP_ALIVE_WITHOUT_CALLS
About the Duration format
To write duration values, use the standard java.time.Duration format.
See the Duration#parse() Java API documentation for more information.
You can also use a simplified format, starting with a number:
When you disable quarkus.grpc.server.use-separate-server, you are then using the new Vert.x gRPC server implementation
which uses the existing HTTP server. Which means that the server port is now 8080 (or the port configured with quarkus.http.port).
Also, most of the other configuration properties are no longer applied, since it’s the HTTP server that should already be properly configured.
quarkus.grpc.server.ssl.certificate=tls/server.pem
quarkus.grpc.server.ssl.key=tls/server.key
quarkus.grpc.server.ssl.trust-store=tls/ca.jks
quarkus.grpc.server.ssl.trust-store-password=*****
quarkus.grpc.server.ssl.client-auth=REQUIRED
When Quarkus builds a gRPC server instance, users can apply their own Server(Builder) customizers. The customizers are applied by priority, the higher the number the later customizer is applied. The customizers are applied before Quarkus applies user’s server configuration; e.g. ideal for some initial defaults.
There are two customize methods, the first one uses gRPC’s ServerBuilder as a parameter - to be used with Quarkus' legacy gRPC support, where the other uses GrpcServerOptions - to be used with the new Vert.x gRPC support. User should implement the right customize method per gRPC support type usage, or both if the customizer is gRPC type neutral.
public interface ServerBuilderCustomizer<T extends ServerBuilder<T>> {
* Customize a ServerBuilder instance.
* @param config server's configuration
* @param builder Server builder instance
default void customize(GrpcServerConfiguration config, T builder) {
* Customize a GrpcServerOptions instance.
* @param config server's configuration
* @param options GrpcServerOptions instance
default void customize(GrpcServerConfiguration config, GrpcServerOptions options) {
* Priority by which the customizers are applied.
* Higher priority is applied later.
* @return the priority
default int priority() {
return 0;
gRPC server interceptors let you perform logic, such as authentication, before your service is invoked.
You can implement a gRPC server interceptor by creating an @ApplicationScoped bean implementing io.grpc.ServerInterceptor:
@ApplicationScoped
// add @GlobalInterceptor for interceptors meant to be invoked for every service
public class MyInterceptor implements ServerInterceptor {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall,
Metadata metadata, ServerCallHandler<ReqT, RespT> serverCallHandler) {
// ...
It’s also possible to annotate a producer method as a global interceptor:
import io.quarkus.grpc.GlobalInterceptor;
import jakarta.enterprise.inject.Produces;
public class MyProducer {
@GlobalInterceptor
@Produces
public MyInterceptor myInterceptor() {
return new MyInterceptor();
To apply an interceptor to all exposed services, annotate it with @io.quarkus.grpc.GlobalInterceptor.
To apply an interceptor to a single service, register it on the service with @io.quarkus.grpc.RegisterInterceptor:
import io.quarkus.grpc.GrpcService;
import io.quarkus.grpc.RegisterInterceptor;
@GrpcService
@RegisterInterceptor(MyInterceptor.class)
public class StreamingService implements Streaming {
// ...
When you have multiple server interceptors, you can order them by implementing the jakarta.enterprise.inject.spi.Prioritized interface. Please note that all the global interceptors are invoked before the service-specific
interceptors.
@ApplicationScoped
public class MyInterceptor implements ServerInterceptor, Prioritized {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall,
Metadata metadata, ServerCallHandler<ReqT, RespT> serverCallHandler) {
// ...
@Override
public int getPriority() {
return 10;
Interceptors with the highest priority are called first.
The default priority, used if the interceptor does not implement the Prioritized interface, is 0.
There is also a support to inject Vert.x RoutingContext instance into your gRPC service, if / when needed.
Quarkus doesn’t do that by default, you will need to add RoutingContextGrpcInterceptor to your gRPC service.
@GrpcService
@RegisterInterceptor(RoutingContextGrpcInterceptor.class)
public class HelloWorldService extends GreeterGrpc.GreeterImplBase {
@Inject
RoutingContext context;
// ...
The easiest way to test a gRPC service is to use a gRPC client as described
in Consuming a gRPC Service .
Please note that in the case of using a client to test an exposed service that does not use TLS,
there is no need to provide any configuration. E.g. to test the HelloService
defined above, one could create the following test:
public class HelloServiceTest implements Greeter {
@GrpcClient
Greeter client;
@Test
void shouldReturnHello() {
CompletableFuture<String> message = new CompletableFuture<>();
client.sayHello(HelloRequest.newBuilder().setName("Quarkus").build())
.subscribe().with(reply -> message.complete(reply.getMessage()));
assertThat(message.get(5, TimeUnit.SECONDS)).isEqualTo("Hello Quarkus");
In the dev mode, you can try out your gRPC services in the Quarkus Dev UI.
Just go to http://localhost:8080/q/dev-ui and click on Services under the gRPC tile.
Please note that your application needs to expose the "normal" HTTP port for the Dev UI to be accessible. If your application does not expose any HTTP endpoints, you can create a dedicated profile with a dependency on quarkus-vertx-http:
<profiles>
<profile>
<id>development</id>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-vertx-http</artifactId>
</dependency>
</dependencies>
</profile>
</profiles>
Having it, you can run the dev mode with: mvn quarkus:dev -Pdevelopment.
If you use Gradle, you can simply add a dependency for the quarkusDev task:
dependencies {
quarkusDev 'io.quarkus:quarkus-vertx-http'
gRPC server metrics are automatically enabled when the application also uses the quarkus-micrometer extension.
Micrometer collects the metrics of all the gRPC services implemented by the application.
As an example, if you export the metrics to Prometheus, you will get:
# HELP grpc_server_responses_sent_messages_total The total number of responses sent
# TYPE grpc_server_responses_sent_messages_total counter
grpc_server_responses_sent_messages_total{method="SayHello",methodType="UNARY",service="helloworld.Greeter",} 6.0
# HELP grpc_server_processing_duration_seconds The total time taken for the server to complete the call
# TYPE grpc_server_processing_duration_seconds summary
grpc_server_processing_duration_seconds_count{method="SayHello",methodType="UNARY",service="helloworld.Greeter",statusCode="OK",} 6.0
grpc_server_processing_duration_seconds_sum{method="SayHello",methodType="UNARY",service="helloworld.Greeter",statusCode="OK",} 0.016216771
# HELP grpc_server_processing_duration_seconds_max The total time taken for the server to complete the call
# TYPE grpc_server_processing_duration_seconds_max gauge
grpc_server_processing_duration_seconds_max{method="SayHello",methodType="UNARY",service="helloworld.Greeter",statusCode="OK",} 0.007985236
# HELP grpc_server_requests_received_messages_total The total number of requests received
# TYPE grpc_server_requests_received_messages_total counter
grpc_server_requests_received_messages_total{method="SayHello",methodType="UNARY",service="helloworld.Greeter",} 6.0
The service name, method and type can be found in the tags .
To disable the gRPC server metrics when quarkus-micrometer is used, add the following property to the application configuration:
quarkus.micrometer.binder.grpc-server.enabled=false
Quarkus includes built-in security to allow authorization using annotations when the Vert.x gRPC support, which uses existing Vert.x HTTP server, is enabled.
Security capabilities are provided by the Quarkus Security extension, therefore make sure your pom.xml file contains following dependency:
pom.xml
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security</artifactId>
</dependency>
To add the Quarkus Security extension to an existing Maven project, run the following command from your project base directory:
quarkus extension add security
Maven
./mvnw quarkus:add-extension -Dextensions='security'
Gradle
./gradlew addExtension --extensions='security'
Some supported authentication mechanisms are built into Quarkus, while others require you to add an extension.
The following table maps specific authentication requirements to a supported mechanism that you can use in Quarkus:
Table 1. Authentication requirements and mechanisms
Do not forget to install at least one extension that provides an IdentityProvider based on selected authentication requirements.
Please refer to the Basic authentication guide for example how to provide the IdentityProvider based on username and password.
If you use separate HTTP server to serve gRPC requests, Custom authentication is your only option.
Set the quarkus.grpc.server.use-separate-server configuration property to false so that you can use other mechanisms.
import hello.Greeter;
import io.quarkus.grpc.GrpcService;
import jakarta.annotation.security.RolesAllowed;
@GrpcService
public class HelloService implements Greeter {
@RolesAllowed("admin")
@Override
public Uni<HelloReply> sayHello(HelloRequest request) {
return Uni.createFrom().item(() ->
HelloReply.newBuilder().setMessage("Hello " + request.getName()).build()
Most of the examples of the supported mechanisms sends authentication headers, please refer to the gRPC Headers
section of the Consuming a gRPC Service guide for more information about the gRPC headers.
Quarkus Security provides built-in authentication support for the Basic authentication .
quarkus.grpc.server.use-separate-server=false
quarkus.http.auth.basic=true (1)
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import org.acme.proto.Greeter;
import org.acme.proto.HelloRequest;
import io.grpc.Metadata;
import io.quarkus.grpc.GrpcClient;
import io.quarkus.grpc.GrpcClientUtils;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
@QuarkusTest
public class GreeterServiceTest {
private static final Metadata.Key<String> AUTHORIZATION = Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER);
@GrpcClient
Greeter greeterClient;
@Test
void shouldReturnHello() throws ExecutionException, InterruptedException, TimeoutException {
Metadata headers = new Metadata();
// Set the headers - Basic auth for testing
headers.put(AUTHORIZATION, "Basic YWxpY2U6YWxpY2U="); // alice:alice with "admin" role
var client = GrpcClientUtils.attachHeaders(greeterClient, headers);
// Call the client
CompletableFuture<String> message = new CompletableFuture<>();
client.sayHello(HelloRequest.newBuilder().setName("Quarkus").build())
.subscribe().with(reply -> message.complete(reply.getMessage()));
// Get the values
String theValue = message.get(5, TimeUnit.SECONDS);
// Assert
assertThat(theValue, is("Hello Quarkus"));
Quarkus provides mutual TLS (mTLS) authentication so that you can authenticate users based on their X.509 certificates.
The simplest way to enforce authentication for all your gRPC services is described in the TLS with Mutual Auth section of this guide.
However, the Quarkus Security supports role mapping that you can use to perform even more fine-grained access control.
quarkus.grpc.server.use-separate-server=false
quarkus.http.insecure-requests=disabled
quarkus.http.ssl.certificate.files=tls/server.pem
quarkus.http.ssl.certificate.key-files=tls/server.key
quarkus.http.ssl.certificate.trust-store-file=tls/ca.jks
quarkus.http.ssl.certificate.trust-store-password=**********
quarkus.http.ssl.client-auth=required
quarkus.http.auth.certificate-role-properties=role-mappings.txt (1)
quarkus.native.additional-build-args=-H:IncludeResources=.*\\.txt
You can always implement one or more GrpcSecurityMechanism bean if above-mentioned mechanisms provided by Quarkus do no meet your needs.
Example of custom GrpcSecurityMechanism
package org.acme.grpc.auth;
import jakarta.inject.Singleton;
import io.grpc.Metadata;
import io.quarkus.security.credential.PasswordCredential;
import io.quarkus.security.identity.request.AuthenticationRequest;
import io.quarkus.security.identity.request.UsernamePasswordAuthenticationRequest;
@Singleton
public class CustomGrpcSecurityMechanism implements GrpcSecurityMechanism {
private static final Metadata.Key<String> AUTHORIZATION = Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER);
@Override
public boolean handles(Metadata metadata) {
String authString = metadata.get(AUTHORIZATION);
return authString != null && authString.startsWith("Custom ");
@Override
public AuthenticationRequest createAuthenticationRequest(Metadata metadata) {
final String authString = metadata.get(AUTHORIZATION);
final String userName;
final String password;
// here comes your application logic that transforms 'authString' to user name and password
return new UsernamePasswordAuthenticationRequest(userName, new PasswordCredential(password));
Generated Code
Implementing a Service with the Mutiny API
Implementing a Service with the default gRPC API
Blocking Service Implementation
Handling Streams
Health Check
Reflection Service
Scaling
Server Configuration
Example of Configuration
Enabling TLS
TLS with Mutual Auth
Custom server building
Server Interceptors
Testing your services
Trying out your services manually
gRPC Server metrics
Enabling metrics collection
Disabling metrics collection
Use virtual threads
gRPC Server authorization
Add the Quarkus Security extension
Overview of supported authentication mechanisms
Secure gRPC service
Basic authentication
Mutual TLS authentication
Custom authentication
Quarkus is open. All dependencies of this project are available under the Apache Software License 2.0 or compatible license. CC by 3.0 This website was built with Jekyll , is hosted on GitHub Pages and is completely open source. If you want to make it better, fork the website and show us what you’ve got.
Navigation
About
Podcast
User Stories
Security policy
Usage
Brand
Wallpapers
Privacy Policy