Protocol Buffer APIs

Secured Kratos gRPC APIs

Access the generated microservices over ultra-fast gRPC using Kratos framework, fully authenticated by Keycloak.

Overview

The GO-DUCK CLI generated app binds the Gin REST webserver on port 8080 and simultaneously spins up an optimized Go-Kratos gRPC listener on port 9000. Both the REST and gRPC handlers share the exact same clean Repository architecture underneath, guaranteeing 100% data and logic consistency.

Automatic Compilation

api/v1/*.proto definitions are generated automatically whenever you add an entity or change fields.

Client Connection Example (Go)

This snippet demonstrates how a developer orchestrating another microservice connects securely using Google's clientcredentials to fulfill the Kratos Auth Header standards.

Crucial Architecture Note (Server-to-Server)

If an event triggers a gRPC call asynchronously in the background (meaning there is NO active human user pushing a token from a frontend), the calling microservice must authenticate itself using a Keycloak Service Account.

The calling server sends its own Client ID and Client Secret directly to Keycloak's Token Endpoint using the Client Credentials Grant flow. Keycloak responds with a valid JWT representing the "Server", which is then injected into the gRPC dialer below.

grpc_client.go
Go
import (
    "context"
    "log"
    "google.golang.org/grpc"
    "golang.org/x/oauth2/clientcredentials"
    pb "go-duck/api/v1"
)

func main() {
    // 1. Configure the Client Credentials Flow
    // These values should match your go-duck.security block in application-dev.yml
    config := clientcredentials.Config{
        ClientID:     "internal",       // Matches keycloak-client-id
        ClientSecret: "internal",       // Matches keycloak-secret
        TokenURL:     "http://localhost:9080/realms/master/protocol/openid-connect/token",
    }

    // 2. Fetch the token dynamically from Keycloak
    tokenSource := config.TokenSource(context.Background())

    // 3. Dial the local port 9000 (GoDuck Server)
    // grpc.WithPerRPCCredentials injects the automatically updating token into every request!
    conn, err := grpc.Dial("localhost:9000", grpc.WithInsecure(), grpc.WithPerRPCCredentials(tokenSource))
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()

    // 4. Initialize the Kratos-generated gRPC Client
    client := pb.NewEntityServiceClient(conn)

    // 5. Execute Native Network Call over gRPC
    res, err := client.GetEntity(context.Background(), &pb.GetEntityRequest{Id: 1})
    if err != nil {
        log.Fatalf("RPC failed: %v", err)
    }
    
    log.Printf("Successfully Received Data Pipeline Object OVER gRPC: %v", res)
}