A secure gRPC microservices demonstration implementing JWT-based authentication with mutual TLS encryption.
This project demonstrates production-ready security patterns for gRPC services in Go, including:
- JWT Authentication: RSA-2048 signed tokens with comprehensive claims validation
- Mutual TLS (mTLS): Certificate-based encryption and authentication
- Rate Limiting: Protection against brute force attacks
- Password Security: bcrypt password hashing
- Input Validation: Comprehensive validation of all user inputs
- Graceful Shutdown: Proper signal handling for clean shutdowns
- Request Logging: Structured logging with interceptors
- Health Checks: Standard gRPC health checking protocol
- Panic Recovery: Middleware to prevent crashes
The project consists of two independent microservices:
Authenticates users and issues JWT tokens.
- Endpoint:
Auth.Login - Input: Username and password
- Output: Signed JWT token (1-hour validity)
- Security Features:
- bcrypt password hashing
- Rate limiting (1 request per 2 seconds per IP)
- Input validation (username: 1-64 chars, password: 8-128 chars)
- Constant-time comparison to prevent timing attacks
Provides greeting functionality secured by JWT authentication.
- Endpoint:
Greeter.SayHello - Input: Empty (username extracted from JWT)
- Output: Personalized greeting
- Security Features:
- JWT signature verification (RSA)
- Comprehensive claims validation (aud, iss, exp, nbf)
- Token expiration checking
- Go: 1.21 or later
- protoc: Protocol Buffer compiler (optional, for regenerating proto files)
- cfssl: CloudFlare PKI toolkit for certificate generation
# Install Go (if not already installed)
# See: https://golang.org/doc/install
# Install cfssl
go install github.com/cloudflare/cfssl/cmd/...@latest
# Install protoc (optional)
# See: https://grpc.io/docs/protoc-installation/
# Install protoc plugins (optional)
make install-toolsClone and initialize the project:
git clone <repository-url>
cd hello-auth-grpc
make init # Create ~/.hello/ directory
make gencert # Generate certificates and keysIMPORTANT: Use environment variables for credentials (not command-line flags):
export AUTH_USERNAME="admin"
export AUTH_PASSWORD="secureP@ssw0rd123" # Must be 8-128 charactersmake buildThis will:
- Download dependencies
- Generate protobuf code (if protoc is installed)
- Build all binaries to
bin/directory
Terminal 1 - Start Auth Service:
export AUTH_USERNAME="admin"
export AUTH_PASSWORD="secureP@ssw0rd123"
./bin/auth-serverTerminal 2 - Start Hello Service:
./bin/hello-serverTerminal 3 - Authenticate and Get Token:
export AUTH_USERNAME="admin"
export AUTH_PASSWORD="secureP@ssw0rd123"
./bin/auth-clientTerminal 4 - Call Authenticated Service:
./bin/hello-clientExpected output:
hello-client: 2025/11/14 12:00:00 remote server says: Hello, admin!
| Variable | Description | Required | Default |
|---|---|---|---|
AUTH_USERNAME |
Username for authentication | Yes | - |
AUTH_PASSWORD |
Password (8-128 characters) | Yes | - |
HELLO_CONFIG_DIR |
Configuration directory | No | ~/.hello |
./bin/auth-server \
--listen-addr 127.0.0.1:20000 \
--jwt-key ~/.hello/jwt-key.pem \
--tls-crt ~/.hello/auth.pem \
--tls-key ~/.hello/auth-key.pem \
--ca-crt ~/.hello/ca.pem./bin/hello-server \
--listen-addr 127.0.0.1:10000 \
--jwt-key ~/.hello/jwt.pem \
--tls-crt ~/.hello/hello.pem \
--tls-key ~/.hello/hello-key.pem \
--ca-crt ~/.hello/ca.pem./bin/auth-client \
--server-addr 127.0.0.1:20000 \
--jwt-token ~/.hello/.token \
--tls-crt ~/.hello/client.pem \
--tls-key ~/.hello/client-key.pem \
--ca-crt ~/.hello/ca.pem./bin/hello-client \
--server-addr 127.0.0.1:10000 \
--jwt-token ~/.hello/.token \
--tls-crt ~/.hello/client.pem \
--tls-key ~/.hello/client-key.pem \
--ca-crt ~/.hello/ca.pem- Minimum Version: TLS 1.2
- Cipher Suites: Only strong ECDHE ciphers with AES-GCM
- Certificate Validation: Mutual TLS with CA verification
- Key Size: RSA 2048-bit (consider upgrading to 4096-bit for production)
- Algorithm: RS256 (RSA with SHA-256)
- Key Size: 2048-bit RSA
- Token Lifetime: 1 hour
- Claims Validated:
sub(Subject): Usernameaud(Audience): "hello.service"iss(Issuer): "auth.service"exp(Expiration): Automatic validationnbf(Not Before): Automatic validationiat(Issued At): Timestamp
- Rate: 0.5 requests/second (1 request every 2 seconds)
- Burst: 3 requests
- Scope: Per client IP address
- Response: HTTP 429 (Resource Exhausted)
- Minimum Length: 8 characters
- Maximum Length: 128 characters
- Storage: bcrypt hashed (cost factor: 10)
- Comparison: Constant-time to prevent timing attacks
hello-auth-grpc/
├── auth/ # Auth service protobuf definitions
│ ├── auth.proto
│ └── auth.pb.go # Generated code
├── hello/ # Hello service protobuf definitions
│ ├── hello.proto
│ └── hello.pb.go # Generated code
├── cmd/ # Application entry points
│ ├── auth-server/ # Auth server implementation
│ ├── auth-client/ # Auth client implementation
│ ├── hello-server/ # Hello server implementation
│ └── hello-client/ # Hello client implementation
├── pkg/ # Shared packages
│ ├── config/ # Configuration utilities
│ └── logging/ # Logging and interceptors
├── credentials/ # Custom credential providers
│ └── jwt/ # JWT credential implementation
├── certs/ # Certificate configuration files
├── Makefile # Build automation
└── README.md # This file
make all # Initialize, generate certificates, and build
make init # Create configuration directory
make build # Build all binaries
make gencert # Generate certificates and keys
make clean # Remove binaries and generated code
make clean-all # Remove everything including certificates
make test # Run tests with race detection and coverage
make coverage # Generate and view coverage report
make install-tools # Install protobuf compiler plugins# Run all tests
make test
# Run tests with coverage
make coverage
# Run specific package tests
go test -v ./pkg/config/
go test -v ./cmd/auth-server/- Define protobuf service in
<service>/<service>.proto - Generate Go code:
protoc --go_out=. --go-grpc_out=. <service>/<service>.proto - Implement server in
cmd/<service>-server/ - Implement client in
cmd/<service>-client/ - Add to Makefile build targets
Both services implement the standard gRPC health checking protocol:
# Using grpcurl (install: go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest)
grpcurl -plaintext localhost:20000 grpc.health.v1.Health/Check
grpcurl -plaintext localhost:10000 grpc.health.v1.Health/CheckExpected response:
{
"status": "SERVING"
}All services log to stderr with structured format:
auth-server: 2025/11/14 12:00:00 server is starting...
auth-server: 2025/11/14 12:00:01 method=/auth.Auth/Login client=127.0.0.1:54321 code=OK duration=45ms
Services handle SIGTERM and SIGINT signals:
# Send SIGTERM
kill -TERM <pid>
# Or Ctrl+C (SIGINT)Services will:
- Stop accepting new connections
- Wait for active requests to complete
- Clean up resources
- Exit
1. "could not load CA certificate"
- Run
make gencertto generate certificates - Check that
~/.hello/directory exists - Verify certificate files have correct permissions
2. "please provide AUTH_USERNAME and AUTH_PASSWORD"
- Set environment variables before running servers/clients
- Don't use command-line flags for credentials (security risk)
3. "could not connect to remote server"
- Ensure server is running
- Check firewall rules
- Verify server address and port
4. "invalid credentials"
- Verify AUTH_USERNAME and AUTH_PASSWORD match server settings
- Check password meets minimum length requirement (8 chars)
5. "too many login attempts"
- Rate limiting is active
- Wait 2 seconds between attempts
- Check for multiple clients from same IP
6. "invalid authentication token"
- Token may be expired (1-hour lifetime)
- Run auth-client to get new token
- Verify token file exists at
~/.hello/.token
Enable verbose logging:
# Set Go's GODEBUG
export GODEBUG=http2debug=2
# Run with race detector
go run -race ./cmd/auth-server/For production use, consider these additional hardening measures:
-
Certificates
- Use 4096-bit RSA keys or ECDSA P-384
- Implement certificate rotation
- Use short-lived certificates (90 days or less)
- Store private keys in hardware security modules (HSM)
-
Authentication
- Implement multi-factor authentication (MFA)
- Add account lockout after N failed attempts
- Use external identity providers (OAuth2, OIDC)
- Implement refresh token mechanism
-
Authorization
- Add role-based access control (RBAC)
- Implement fine-grained permissions
- Audit all access attempts
-
Network
- Deploy behind load balancer
- Use firewall rules to restrict access
- Enable DDoS protection
- Implement network segmentation
-
Monitoring
- Add Prometheus metrics
- Set up alerting (PagerDuty, Opsgenie)
- Enable distributed tracing (Jaeger, Zipkin)
- Log aggregation (ELK, Loki)
-
Token Management
- Implement token revocation/blacklisting
- Reduce token lifetime (15-30 minutes)
- Add refresh token rotation
- Store tokens securely (encrypted)
Authenticates a user and returns a JWT token.
Request:
message Request {
string username = 1; // 1-64 characters
string password = 2; // 8-128 characters
}Response:
message Response {
string token = 1; // JWT token (1-hour validity)
}Errors:
InvalidArgument: Invalid username or password formatPermissionDenied: Invalid credentialsResourceExhausted: Rate limit exceededInternal: Server error
Returns a personalized greeting for the authenticated user.
Request:
message Request {} // Empty - username from JWTResponse:
message Response {
string message = 1; // Greeting message
}Errors:
Unauthenticated: Missing, invalid, or expired tokenInternal: Server error
Authentication: Include JWT token in request metadata:
authorization: <jwt-token>
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run tests (
make test) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with gRPC
- JWT handling with golang-jwt
- Certificate generation with CFSSL
For issues, questions, or contributions, please open an issue on GitHub.