I'm trying establish a connection to a remote GRPC service (a Camunda Zeebe gateway) with basic authentication:
client, err := zbc.NewClient(&zbc.ClientConfig{
GatewayAddress: gatewayAddress,
DialOpts: []grpcLib.DialOption{grpcLib.WithTransportCredentials(&BasicAuthCredentials{...})},
})
I'm a bit in loss when it comes to the implementation of BasicAuthCredentials
, b/c I don't know how to set the Authorization
header in the net.Conn
object:
import (
"context"
"encoding/base64"
"google.golang.org/grpc/credentials"
"net"
)
type BasicAuthCredentials struct {
username string
password string
}
func (c *BasicAuthCredentials) ClientHandshake(ctx context.Context, s string, conn net.Conn) (net.Conn, credentials.AuthInfo, error) {
// Create the Basic Auth string
auth := b.username + ":" + b.password
encodedAuth := base64.StdEncoding.EncodeToString([]byte(auth))
// TODO set this encoded string as Authentication header
return conn, c, nil
}
func (c *BasicAuthCredentials) AuthType() string {
return "basic-auth"
}
// ... other methods to implement credentials.TransportCredentials
Is there a way, to attach these auth information to the connection, or am I approaching it fundamentally wrong?
You are trying to "alter" connection directly, but gRPC already handles the connection management internally. What you really want is to add authentication information to each RPC call. You should implement GetRequestMetadata instead of trying to set the Authorization header in the net.Conn object.
Implementation should look something like this ->>
package main
import (
"context"
"encoding/base64"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)
func basicAuth(username, password string) grpc.DialOption {
auth := username + ":" + password
encodedAuth := base64.StdEncoding.EncodeToString([]byte(auth))
return grpc.WithPerRPCCredentials(&basicAuthCreds{token: encodedAuth})
}
type basicAuthCreds struct {
token string
}
func (b *basicAuthCreds) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return map[string]string{
"authorization": "Basic " + b.token,
}, nil
}
func (b *basicAuthCreds) RequireTransportSecurity() bool {
return false // Set to true if using TLS
}
Than use it like this
client, err := zbc.NewClient(&zbc.ClientConfig{
GatewayAddress: gatewayAddress,
DialOpts: []grpc.DialOption{
basicAuth("username", "password"),
},
})