or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

admin.mdadvanced.mdclient-server.mdcredentials-security.mderrors-status.mdhealth.mdindex.mdinterceptors.mdload-balancing.mdmetadata-context.mdname-resolution.mdobservability.mdreflection.mdstreaming.mdtesting.mdxds.md
tile.json

credentials-security.mddocs/

Credentials and Security

This document covers credential types, transport security, authentication mechanisms, and security configuration in gRPC-Go.

Overview

The credentials package implements various credentials supported by gRPC, which encapsulate all the state needed by a client to authenticate with a server and make various assertions about the client's identity, role, or authorization.

import "google.golang.org/grpc/credentials"

Transport Credentials

TransportCredentials Interface

Transport credentials define the common interface for all live gRPC wire protocols and supported transport security protocols (e.g., TLS, SSL).

type TransportCredentials interface {
    // ClientHandshake does the authentication handshake for clients.
    // Returns the authenticated connection and auth information.
    // Implementations must use the provided context for timely cancellation.
    // The authority parameter is the :authority header value used for new streams.
    ClientHandshake(ctx context.Context, authority string, rawConn net.Conn) (net.Conn, AuthInfo, error)

    // ServerHandshake does the authentication handshake for servers.
    // Returns the authenticated connection and auth information.
    ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error)

    // Info provides the ProtocolInfo of this TransportCredentials
    Info() ProtocolInfo

    // Clone makes a copy of this TransportCredentials
    Clone() TransportCredentials

    // OverrideServerName specifies the value used for verifying hostname
    // Deprecated: use grpc.WithAuthority instead
    OverrideServerName(string) error
}

TLS Credentials

Client TLS

// NewTLS uses tls.Config to construct TransportCredentials
func NewTLS(c *tls.Config) TransportCredentials

// NewClientTLSFromCert constructs TLS credentials from root CA certificate pool
// serverNameOverride is for testing only - use grpc.WithAuthority in production
func NewClientTLSFromCert(cp *x509.CertPool, serverNameOverride string) TransportCredentials

// NewClientTLSFromFile constructs TLS credentials from root CA certificate file
// serverNameOverride is for testing only - use grpc.WithAuthority in production
func NewClientTLSFromFile(certFile, serverNameOverride string) (TransportCredentials, error)

Client TLS Examples:

import (
    "crypto/tls"
    "crypto/x509"
    "os"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
)

// Basic TLS from file
creds, err := credentials.NewClientTLSFromFile("ca.pem", "")
if err != nil {
    log.Fatalf("failed to load credentials: %v", err)
}
conn, err := grpc.NewClient("example.com:443", grpc.WithTransportCredentials(creds))

// TLS from cert pool
certPool := x509.NewCertPool()
ca, err := os.ReadFile("ca.pem")
if err != nil {
    log.Fatal(err)
}
certPool.AppendCertsFromPEM(ca)
creds := credentials.NewClientTLSFromCert(certPool, "")
conn, err := grpc.NewClient("example.com:443", grpc.WithTransportCredentials(creds))

// Custom TLS config (for mTLS)
cert, err := tls.LoadX509KeyPair("client.pem", "client.key")
if err != nil {
    log.Fatal(err)
}
certPool := x509.NewCertPool()
ca, err := os.ReadFile("ca.pem")
if err != nil {
    log.Fatal(err)
}
certPool.AppendCertsFromPEM(ca)

tlsConfig := &tls.Config{
    Certificates: []tls.Certificate{cert},
    RootCAs:      certPool,
}
creds := credentials.NewTLS(tlsConfig)
conn, err := grpc.NewClient("example.com:443", grpc.WithTransportCredentials(creds))

Server TLS

// NewServerTLSFromCert constructs TLS credentials from certificate for server
func NewServerTLSFromCert(cert *tls.Certificate) TransportCredentials

// NewServerTLSFromFile constructs TLS credentials from certificate and key files
func NewServerTLSFromFile(certFile, keyFile string) (TransportCredentials, error)

Server TLS Examples:

import (
    "crypto/tls"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
)

// TLS from files
creds, err := credentials.NewServerTLSFromFile("server.pem", "server.key")
if err != nil {
    log.Fatalf("failed to load credentials: %v", err)
}
server := grpc.NewServer(grpc.Creds(creds))

// TLS from certificate
cert, err := tls.LoadX509KeyPair("server.pem", "server.key")
if err != nil {
    log.Fatal(err)
}
creds := credentials.NewServerTLSFromCert(&cert)
server := grpc.NewServer(grpc.Creds(creds))

// Custom TLS config (for mTLS with client auth)
cert, err := tls.LoadX509KeyPair("server.pem", "server.key")
if err != nil {
    log.Fatal(err)
}
certPool := x509.NewCertPool()
ca, err := os.ReadFile("ca.pem")
if err != nil {
    log.Fatal(err)
}
certPool.AppendCertsFromPEM(ca)

tlsConfig := &tls.Config{
    Certificates: []tls.Certificate{cert},
    ClientAuth:   tls.RequireAndVerifyClientCert,
    ClientCAs:    certPool,
}
creds := credentials.NewTLS(tlsConfig)
server := grpc.NewServer(grpc.Creds(creds))

Insecure Credentials

For development and testing only:

import "google.golang.org/grpc/credentials/insecure"

// NewCredentials returns credentials which disables transport security
func NewCredentials() credentials.TransportCredentials

// NewBundle returns a bundle with disabled transport security
func NewBundle() credentials.Bundle

Example:

import (
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/insecure"
)

// Client without TLS (testing only)
conn, err := grpc.NewClient("localhost:50051",
    grpc.WithTransportCredentials(insecure.NewCredentials()))

// Server without TLS (testing only)
server := grpc.NewServer()

Local Credentials

For local connections (local TCP or Unix Domain Sockets):

import "google.golang.org/grpc/credentials/local"

// NewCredentials returns local transport credentials
// Reports NoSecurity for local TCP, PrivacyAndIntegrity for UDS
func NewCredentials() credentials.TransportCredentials

Example:

import (
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/local"
)

// Client for Unix Domain Socket
conn, err := grpc.NewClient("unix:///tmp/grpc.sock",
    grpc.WithTransportCredentials(local.NewCredentials()))

// Server for Unix Domain Socket
lis, err := net.Listen("unix", "/tmp/grpc.sock")
server := grpc.NewServer(grpc.Creds(local.NewCredentials()))

Per-RPC Credentials

PerRPCCredentials Interface

Per-RPC credentials attach security information to every RPC (e.g., OAuth tokens).

type PerRPCCredentials interface {
    // GetRequestMetadata gets the current request metadata, refreshing tokens if required.
    // Called by the transport layer on each request.
    // uri is the URI of the entry point for the request.
    // ctx can be used for timeout and cancellation, and contains RequestInfo.
    GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)

    // RequireTransportSecurity indicates whether the credentials requires transport security
    RequireTransportSecurity() bool
}

OAuth2 Credentials

import "google.golang.org/grpc/credentials/oauth"

// TokenSource supplies PerRPCCredentials from an oauth2.TokenSource
type TokenSource struct {
    oauth2.TokenSource
}

func (ts TokenSource) GetRequestMetadata(ctx context.Context, _ ...string) (map[string]string, error)
func (ts TokenSource) RequireTransportSecurity() bool

// Application Default Credentials
func NewApplicationDefault(ctx context.Context, scope ...string) (credentials.PerRPCCredentials, error)

// Compute Engine credentials
func NewComputeEngine() credentials.PerRPCCredentials

// JWT access credentials
func NewJWTAccessFromFile(keyFile string) (credentials.PerRPCCredentials, error)
func NewJWTAccessFromKey(jsonKey []byte) (credentials.PerRPCCredentials, error)

// Service account credentials
func NewServiceAccountFromFile(keyFile string, scope ...string) (credentials.PerRPCCredentials, error)
func NewServiceAccountFromKey(jsonKey []byte, scope ...string) (credentials.PerRPCCredentials, error)

// Static OAuth2 token (deprecated - use TokenSource instead)
func NewOauthAccess(token *oauth2.Token) credentials.PerRPCCredentials

OAuth2 Examples:

import (
    "context"
    "golang.org/x/oauth2"
    "golang.org/x/oauth2/google"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/credentials/oauth"
)

// Application Default Credentials
perRPC, err := oauth.NewApplicationDefault(context.Background(),
    "https://www.googleapis.com/auth/cloud-platform")
if err != nil {
    log.Fatal(err)
}
tlsCreds, _ := credentials.NewClientTLSFromFile("ca.pem", "")
conn, err := grpc.NewClient("example.googleapis.com:443",
    grpc.WithTransportCredentials(tlsCreds),
    grpc.WithPerRPCCredentials(perRPC))

// JWT from service account file
perRPC, err := oauth.NewJWTAccessFromFile("service-account.json")
if err != nil {
    log.Fatal(err)
}
conn, err := grpc.NewClient("example.googleapis.com:443",
    grpc.WithTransportCredentials(tlsCreds),
    grpc.WithPerRPCCredentials(perRPC))

// OAuth2 token source
tokenSource, err := google.DefaultTokenSource(context.Background(),
    "https://www.googleapis.com/auth/cloud-platform")
if err != nil {
    log.Fatal(err)
}
perRPC := oauth.TokenSource{TokenSource: tokenSource}
conn, err := grpc.NewClient("example.googleapis.com:443",
    grpc.WithTransportCredentials(tlsCreds),
    grpc.WithPerRPCCredentials(perRPC))

JWT Token File Credentials

For service mesh environments where JWT tokens are provisioned by infrastructure:

import "google.golang.org/grpc/credentials/jwt"

// NewTokenFileCallCredentials creates PerRPCCredentials that reads JWT tokens from file
// Tokens are cached until expiration
// Requires transport security
// Experimental API
func NewTokenFileCallCredentials(tokenFilePath string) (credentials.PerRPCCredentials, error)

Example:

import (
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/credentials/jwt"
)

// JWT from file (for service mesh)
perRPC, err := jwt.NewTokenFileCallCredentials("/var/run/secrets/tokens/jwt")
if err != nil {
    log.Fatal(err)
}
tlsCreds, _ := credentials.NewClientTLSFromFile("ca.pem", "")
conn, err := grpc.NewClient("example.com:443",
    grpc.WithTransportCredentials(tlsCreds),
    grpc.WithPerRPCCredentials(perRPC))

STS (Security Token Service) Credentials

For token exchange using STS as defined in RFC 8693:

import "google.golang.org/grpc/credentials/sts"

type Options struct {
    // TokenExchangeServiceURI is the address of the STS server (required)
    TokenExchangeServiceURI string

    // Resource is a URI indicating the target service (optional)
    Resource string

    // Audience is the logical name of the target service (optional)
    Audience string

    // Scope is a list of space-delimited scopes (optional)
    // Default: https://www.googleapis.com/auth/cloud-platform
    Scope string

    // RequestedTokenType is the type of requested security token (optional)
    RequestedTokenType string

    // SubjectTokenPath is the path to the file containing the subject token (required)
    SubjectTokenPath string

    // SubjectTokenType is the type of subject token (required)
    SubjectTokenType string

    // ActorTokenPath is the path to the file containing the actor token (optional)
    ActorTokenPath string

    // ActorTokenType is the type of actor token (optional)
    ActorTokenType string
}

// NewCredentials returns new PerRPCCredentials using STS token exchange
// Experimental API
func NewCredentials(opts Options) (credentials.PerRPCCredentials, error)

Example:

import (
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/credentials/sts"
)

// STS credentials
opts := sts.Options{
    TokenExchangeServiceURI: "https://sts.example.com/v1/token",
    Resource:                "https://backend.example.com",
    Audience:                "example-service",
    SubjectTokenPath:        "/var/run/secrets/tokens/subject",
    SubjectTokenType:        "urn:ietf:params:oauth:token-type:jwt",
}
perRPC, err := sts.NewCredentials(opts)
if err != nil {
    log.Fatal(err)
}
tlsCreds, _ := credentials.NewClientTLSFromFile("ca.pem", "")
conn, err := grpc.NewClient("example.com:443",
    grpc.WithTransportCredentials(tlsCreds),
    grpc.WithPerRPCCredentials(perRPC))

Custom Per-RPC Credentials

Implement the PerRPCCredentials interface for custom authentication:

type MyCredentials struct {
    Token string
}

func (c *MyCredentials) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
    return map[string]string{
        "authorization": "Bearer " + c.Token,
    }, nil
}

func (c *MyCredentials) RequireTransportSecurity() bool {
    return true
}

// Usage
creds := &MyCredentials{Token: "my-token"}
tlsCreds, _ := credentials.NewClientTLSFromFile("ca.pem", "")
conn, err := grpc.NewClient("example.com:443",
    grpc.WithTransportCredentials(tlsCreds),
    grpc.WithPerRPCCredentials(creds))

Credentials Bundle

A Bundle combines transport and per-RPC credentials with mode switching:

type Bundle interface {
    // TransportCredentials returns transport credentials from the bundle
    // Must return non-nil. Use insecure.NewCredentials() if not needed.
    TransportCredentials() TransportCredentials

    // PerRPCCredentials returns per-RPC credentials from the bundle
    // May be nil if not needed
    PerRPCCredentials() PerRPCCredentials

    // NewWithMode creates a copy of Bundle with switched mode
    // Returns nil if the requested mode is not supported
    NewWithMode(mode string) (Bundle, error)
}

Google Credentials

Pre-configured bundles for Google Cloud services:

import "google.golang.org/grpc/credentials/google"

type DefaultCredentialsOptions struct {
    // PerRPCCreds is per-RPC credentials passed to bundle
    PerRPCCreds credentials.PerRPCCredentials

    // ALTSPerRPCCreds supersedes PerRPCCreds for ALTS connections
    ALTSPerRPCCreds credentials.PerRPCCredentials
}

// NewDefaultCredentials returns a bundle configured for Google services
// Experimental API
func NewDefaultCredentials() credentials.Bundle

// NewDefaultCredentialsWithOptions returns a bundle with custom options
// Experimental API
func NewDefaultCredentialsWithOptions(opts DefaultCredentialsOptions) credentials.Bundle

// NewComputeEngineCredentials returns a bundle for GCE VM default service account
// Must only be used when running on GCE
// Experimental API
func NewComputeEngineCredentials() credentials.Bundle

Example:

import (
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/google"
)

// Default Google credentials
creds := google.NewDefaultCredentials()
conn, err := grpc.NewClient("example.googleapis.com:443",
    grpc.WithCredentialsBundle(creds))

// Compute Engine credentials
creds := google.NewComputeEngineCredentials()
conn, err := grpc.NewClient("example.googleapis.com:443",
    grpc.WithCredentialsBundle(creds))

ALTS (Application Layer Transport Security)

ALTS is Google's mutual authentication and transport encryption system for internal services:

import "google.golang.org/grpc/credentials/alts"

type ClientOptions struct {
    // TargetServiceAccounts contains expected target service accounts
    TargetServiceAccounts []string

    // HandshakerServiceAddress is the ALTS handshaker service address
    HandshakerServiceAddress string
}

type ServerOptions struct {
    // HandshakerServiceAddress is the ALTS handshaker service address
    HandshakerServiceAddress string
}

// NewClientCreds constructs client-side ALTS TransportCredentials
func NewClientCreds(opts *ClientOptions) credentials.TransportCredentials

// NewServerCreds constructs server-side ALTS TransportCredentials
func NewServerCreds(opts *ServerOptions) credentials.TransportCredentials

// DefaultClientOptions creates ClientOptions with default values
func DefaultClientOptions() *ClientOptions

// DefaultServerOptions creates ServerOptions with default values
func DefaultServerOptions() *ServerOptions

// ClientAuthorizationCheck verifies client authorization based on service accounts
// Should be called in gRPC server RPC handlers
func ClientAuthorizationCheck(ctx context.Context, expectedServiceAccounts []string) error

ALTS Examples:

import (
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/alts"
)

// ALTS client
opts := alts.DefaultClientOptions()
opts.TargetServiceAccounts = []string{"service1@example.iam.gserviceaccount.com"}
creds := alts.NewClientCreds(opts)
conn, err := grpc.NewClient("example.com:443", grpc.WithTransportCredentials(creds))

// ALTS server
opts := alts.DefaultServerOptions()
creds := alts.NewServerCreds(opts)
server := grpc.NewServer(grpc.Creds(creds))

// Server-side authorization check
func (s *server) MyMethod(ctx context.Context, req *pb.Request) (*pb.Response, error) {
    if err := alts.ClientAuthorizationCheck(ctx,
        []string{"client@example.iam.gserviceaccount.com"}); err != nil {
        return nil, status.Error(codes.PermissionDenied, "unauthorized")
    }
    // Process request
}

ALTS AuthInfo

Extract ALTS authentication information:

type AuthInfo interface {
    ApplicationProtocol() string
    RecordProtocol() string
    SecurityLevel() altspb.SecurityLevel
    PeerServiceAccount() string
    LocalServiceAccount() string
    PeerRPCVersions() *altspb.RpcProtocolVersions
}

// AuthInfoFromContext extracts ALTS AuthInfo from context (server-side)
func AuthInfoFromContext(ctx context.Context) (AuthInfo, error)

// AuthInfoFromPeer extracts ALTS AuthInfo from peer (client-side)
func AuthInfoFromPeer(p *peer.Peer) (AuthInfo, error)

Example:

import (
    "google.golang.org/grpc/credentials/alts"
    "google.golang.org/grpc/peer"
)

// Server-side: get ALTS info from context
func (s *server) MyMethod(ctx context.Context, req *pb.Request) (*pb.Response, error) {
    authInfo, err := alts.AuthInfoFromContext(ctx)
    if err != nil {
        return nil, err
    }
    fmt.Printf("Peer service account: %s\n", authInfo.PeerServiceAccount())
    // Process request
}

// Client-side: get ALTS info from peer
var p peer.Peer
resp, err := client.MyMethod(ctx, req, grpc.Peer(&p))
if err == nil {
    authInfo, err := alts.AuthInfoFromPeer(&p)
    if err == nil {
        fmt.Printf("Connected to: %s\n", authInfo.PeerServiceAccount())
    }
}

xDS Credentials

Transport credentials with security configuration pushed by xDS management server:

import "google.golang.org/grpc/credentials/xds"

type ClientOptions struct {
    // FallbackCreds used when xds scheme not used or no security config from management server
    // Required - creation will fail without fallback credentials
    FallbackCreds credentials.TransportCredentials
}

type ServerOptions struct {
    // FallbackCreds used when management server returns no security config
    // Required - creation will fail without fallback credentials
    FallbackCreds credentials.TransportCredentials
}

// NewClientCredentials returns client-side xDS transport credentials
func NewClientCredentials(opts ClientOptions) (credentials.TransportCredentials, error)

// NewServerCredentials returns server-side xDS transport credentials
func NewServerCredentials(opts ServerOptions) (credentials.TransportCredentials, error)

Example:

import (
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/credentials/xds"
)

// xDS client credentials
fallback, _ := credentials.NewClientTLSFromFile("ca.pem", "")
xdsCreds, err := xds.NewClientCredentials(xds.ClientOptions{
    FallbackCreds: fallback,
})
if err != nil {
    log.Fatal(err)
}
conn, err := grpc.NewClient("xds:///my-service", grpc.WithTransportCredentials(xdsCreds))

// xDS server credentials
fallback, _ := credentials.NewServerTLSFromFile("server.pem", "server.key")
xdsCreds, err := xds.NewServerCredentials(xds.ServerOptions{
    FallbackCreds: fallback,
})
if err != nil {
    log.Fatal(err)
}
server := grpc.NewServer(grpc.Creds(xdsCreds))

AuthInfo

AuthInfo defines the common interface for authentication information:

type AuthInfo interface {
    AuthType() string
}

TLSInfo

type TLSInfo struct {
    State tls.ConnectionState
    CommonAuthInfo
    SPIFFEID *url.URL // Experimental
}

func (t TLSInfo) AuthType() string
func (t TLSInfo) GetSecurityValue() ChannelzSecurityValue
func (t TLSInfo) ValidateAuthority(authority string) error

CommonAuthInfo

type CommonAuthInfo struct {
    SecurityLevel SecurityLevel
}

func (c CommonAuthInfo) GetCommonAuthInfo() CommonAuthInfo

SecurityLevel

type SecurityLevel int

const (
    // InvalidSecurityLevel indicates invalid security level (zero value)
    InvalidSecurityLevel SecurityLevel = iota

    // NoSecurity indicates insecure connection
    NoSecurity

    // IntegrityOnly indicates integrity protection only
    IntegrityOnly

    // PrivacyAndIntegrity indicates both privacy and integrity protection
    PrivacyAndIntegrity
)

func (s SecurityLevel) String() string
func CheckSecurityLevel(ai AuthInfo, level SecurityLevel) error

RequestInfo

Request data available to GetRequestMetadata calls:

type RequestInfo struct {
    // The method passed to Invoke or NewStream (e.g., "/some.Service/Method")
    Method string

    // AuthInfo from security handshake
    AuthInfo AuthInfo
}

// RequestInfoFromContext extracts RequestInfo from context
// Experimental API
func RequestInfoFromContext(ctx context.Context) (ri RequestInfo, ok bool)

// NewContextWithRequestInfo creates context with RequestInfo attached
// For testing PerRPCCredentials implementations
// Experimental API
func NewContextWithRequestInfo(ctx context.Context, ri RequestInfo) context.Context

Protocol Info

type ProtocolInfo struct {
    // Deprecated: unused by gRPC
    ProtocolVersion string

    // SecurityProtocol is the security protocol in use
    SecurityProtocol string

    // Deprecated: use Peer.AuthInfo instead
    SecurityVersion string

    // Deprecated: use grpc.WithAuthority instead
    ServerName string
}

Authority Validation

type AuthorityValidator interface {
    // ValidateAuthority checks the authority value used to override :authority header
    // Returns non-nil error if validation fails
    ValidateAuthority(authority string) error
}

TLSInfo implements AuthorityValidator and validates against peer certificates.

Client-Side Usage

import (
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
)

// Transport credentials only
tlsCreds, _ := credentials.NewClientTLSFromFile("ca.pem", "")
conn, err := grpc.NewClient("example.com:443",
    grpc.WithTransportCredentials(tlsCreds))

// Transport + per-RPC credentials
tlsCreds, _ := credentials.NewClientTLSFromFile("ca.pem", "")
perRPC, _ := oauth.NewApplicationDefault(ctx)
conn, err := grpc.NewClient("example.com:443",
    grpc.WithTransportCredentials(tlsCreds),
    grpc.WithPerRPCCredentials(perRPC))

// Credentials bundle
bundle := google.NewDefaultCredentials()
conn, err := grpc.NewClient("example.googleapis.com:443",
    grpc.WithCredentialsBundle(bundle))

Server-Side Usage

import (
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
)

// Transport credentials
creds, _ := credentials.NewServerTLSFromFile("server.pem", "server.key")
server := grpc.NewServer(grpc.Creds(creds))

// Extract auth info in handlers
func (s *server) MyMethod(ctx context.Context, req *pb.Request) (*pb.Response, error) {
    p, ok := peer.FromContext(ctx)
    if ok {
        tlsInfo := p.AuthInfo.(credentials.TLSInfo)
        fmt.Printf("Client cert CN: %s\n", tlsInfo.State.PeerCertificates[0].Subject.CommonName)
    }
    // Process request
}

Best Practices

Security

  1. Always use TLS in production: Use insecure.NewCredentials() only for local development
  2. Verify server identity: Don't use serverNameOverride in production
  3. Rotate credentials: Implement credential rotation for long-lived services
  4. Mutual TLS: Use mTLS (client certificates) for service-to-service communication
  5. Least privilege: Grant minimum required scopes/permissions

Per-RPC Credentials

  1. Token refresh: Implement proper token refresh logic in GetRequestMetadata
  2. Caching: Cache tokens until expiration to avoid excessive refreshes
  3. Error handling: Return appropriate status codes from GetRequestMetadata
  4. Require TLS: Set RequireTransportSecurity() to true unless you have specific reasons

Testing

import (
    "testing"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/insecure"
    "google.golang.org/grpc/test/bufconn"
)

// Use bufconn for in-memory testing
func TestMyService(t *testing.T) {
    lis := bufconn.Listen(1024 * 1024)
    server := grpc.NewServer()
    pb.RegisterMyServiceServer(server, &myServer{})
    go server.Serve(lis)
    defer server.Stop()

    conn, _ := grpc.NewClient("bufnet",
        grpc.WithContextDialer(func(ctx context.Context, s string) (net.Conn, error) {
            return lis.DialContext(ctx)
        }),
        grpc.WithTransportCredentials(insecure.NewCredentials()))
    defer conn.Close()

    client := pb.NewMyServiceClient(conn)
    // Test RPCs
}