e071084ebe
govulncheck / govulncheck (push) Waiting to run
Harness (E2E) / Harnesses (mock LLM) (push) Waiting to run
Harness (E2E) / Provider harnesses (live LLM conformance) (push) Waiting to run
Lint / golangci-lint (push) Waiting to run
Run Tests / Unit Tests (push) Waiting to run
Run Tests / Etcd Integration Tests (push) Waiting to run
10 KiB
10 KiB
Auth Example
This example demonstrates how to use the auth wrappers to protect your microservices with authentication and authorization.
Overview
The example includes:
-
Server - A Greeter service with:
- Protected endpoint:
Greeter.Hello(requires auth) - Public endpoint:
Greeter.Health(no auth required)
- Protected endpoint:
-
Client - Makes calls to the server:
- With authentication (successful)
- Without authentication (fails as expected)
Architecture
┌─────────────────────────────────────────┐
│ Client │
│ ┌────────────────────────────────┐ │
│ │ AuthClient Wrapper │ │
│ │ - Adds Bearer token │ │
│ │ - To all requests │ │
│ └────────────────────────────────┘ │
└──────────────┬──────────────────────────┘
│ RPC with Authorization: Bearer <token>
│
▼
┌─────────────────────────────────────────┐
│ Server │
│ ┌────────────────────────────────┐ │
│ │ AuthHandler Wrapper │ │
│ │ - Extracts token │ │
│ │ - Verifies with auth.Inspect()│ │
│ │ - Checks with rules.Verify() │ │
│ │ - Returns 401/403 if denied │ │
│ └────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────┐ │
│ │ Handler (Greeter.Hello) │ │
│ │ - Gets account from context │ │
│ │ - Processes request │ │
│ └────────────────────────────────┘ │
└─────────────────────────────────────────┘
Files
examples/auth/
├── README.md # This file
├── proto/
│ ├── greeter.proto # Service definition
│ └── greeter.pb.go # Generated Go code
├── server/
│ └── main.go # Protected service
└── client/
└── main.go # Client with auth
Running the Example
1. Start the Server
cd server
go run main.go
The server will:
- Start the Greeter service
- Apply auth wrapper to protect endpoints
- Generate a test token and print it
Output:
=== Test Token Generated ===
Use this token to test the client:
TOKEN=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9... go run client/main.go
2026/02/11 10:00:00 Server [greeter] Listening on [::]:54321
2. Run the Client (With Auth)
In a new terminal:
cd client
TOKEN=<token-from-server> go run main.go
Output:
=== Test 1: Protected endpoint WITH auth ===
Response: Hello, test-user!
=== Test 2: Public endpoint (no auth needed) ===
Health Status: ok
=== Test 3: Protected endpoint WITHOUT auth (should fail) ===
Expected error: {"id":"greeter","code":401,"detail":"missing authorization token","status":"Unauthorized"}
3. Run the Client (Without Auth)
cd client
go run main.go
This will auto-generate a token for testing.
Code Walkthrough
Server Setup
// 1. Create auth provider
// For this example we use the noop auth (accepts all tokens)
// In production, use JWT or a custom auth provider
authProvider := noop.NewAuth()
// 2. Create authorization rules
rules := auth.NewRules()
rules.Grant(&auth.Rule{
ID: "public-health",
Scope: "",
Resource: &auth.Resource{Endpoint: "Greeter.Health"},
Access: auth.AccessGranted,
})
// 3. Wrap service with auth handler
service := micro.NewService(
micro.Name("greeter"),
micro.WrapHandler(
authWrapper.AuthHandler(authWrapper.HandlerOptions{
Auth: authProvider,
Rules: rules,
SkipEndpoints: []string{"Greeter.Health"},
}),
),
)
Client Setup
// 1. Get or generate token
token := os.Getenv("TOKEN")
// 2. Wrap client with auth
service := micro.NewService(
micro.Name("greeter.client"),
micro.WrapClient(
authWrapper.FromToken(token),
),
)
// 3. Make calls (token automatically added)
greeterClient := pb.NewGreeterService("greeter", service.Client())
rsp, err := greeterClient.Hello(ctx, &pb.Request{Name: "John"})
Handler Implementation
func (g *Greeter) Hello(ctx context.Context, req *pb.Request, rsp *pb.Response) error {
// Get account from context (added by auth wrapper)
acc, ok := auth.AccountFromContext(ctx)
if !ok {
return errors.Unauthorized("greeter", "authentication required")
}
rsp.Msg = "Hello, " + acc.ID + "!"
return nil
}
Auth Wrapper Features
Server Wrapper (AuthHandler)
- Token Extraction: Reads
Authorization: Bearer <token>from metadata - Token Verification: Validates token using
auth.Inspect() - Authorization: Checks permissions using
rules.Verify() - Context Injection: Adds account to context for handlers
- Error Handling: Returns 401/403 with clear error messages
- Skip Endpoints: Allows public endpoints without auth
Client Wrapper (AuthClient)
- Automatic Token Injection: Adds Bearer token to all requests
- Context-Aware: Can extract account from context
- Static Token: Use
FromToken()for pre-generated tokens - Dynamic Token: Use
FromContext()to generate per-request
Auth Strategies
1. All Endpoints Protected
micro.WrapHandler(
authWrapper.AuthRequired(authProvider, rules),
)
2. Some Public Endpoints
micro.WrapHandler(
authWrapper.PublicEndpoints(authProvider, rules, []string{
"Health.Check",
"Status.Version",
}),
)
3. Optional Auth (Extract but Don't Enforce)
micro.WrapHandler(
authWrapper.AuthOptional(authProvider),
)
Authorization Rules
Grant Public Access
rules.Grant(&auth.Rule{
ID: "public",
Scope: "", // No scope = public
Resource: &auth.Resource{Endpoint: "Health.Check"},
Access: auth.AccessGranted,
})
Require Authentication
rules.Grant(&auth.Rule{
ID: "authenticated",
Scope: "*", // Any authenticated user
Resource: &auth.Resource{Endpoint: "*"},
Access: auth.AccessGranted,
})
Require Specific Scope
rules.Grant(&auth.Rule{
ID: "admin-only",
Scope: "admin", // Only admin scope
Resource: &auth.Resource{Endpoint: "Admin.*"},
Access: auth.AccessGranted,
})
Deny Access
rules.Grant(&auth.Rule{
ID: "deny-delete",
Scope: "*",
Resource: &auth.Resource{Endpoint: "User.Delete"},
Access: auth.AccessDenied,
Priority: 100, // Higher priority = evaluated first
})
Testing Without Server
You can test auth logic without a running server:
import "go-micro.dev/v5/auth/noop"
// Create auth provider (noop for testing)
authProvider := noop.NewAuth()
// Generate account
acc, _ := authProvider.Generate("test-user", auth.WithScopes("admin"))
// Generate token
token, _ := authProvider.Token(auth.WithCredentials(acc.ID, acc.Secret))
// Verify token
verified, _ := authProvider.Inspect(token.AccessToken)
fmt.Println(verified.ID) // Returns a generated UUID
Production Considerations
1. Use Production Auth Provider
The noop auth provider (auth.NewAuth()) is for development only. It accepts any token.
For production, implement a proper auth provider or use the JWT implementation:
// Option 1: Implement custom auth.Auth interface
type MyAuth struct {
// Your implementation
}
func (m *MyAuth) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) {
// Generate real accounts
}
func (m *MyAuth) Inspect(token string) (*auth.Account, error) {
// Verify real tokens (JWT, OAuth, etc.)
}
// Option 2: Use JWT auth (requires jwt package implementation)
// Note: The jwt package in auth/jwt depends on an external plugin
// You may need to implement your own JWT auth or use a third-party library
3. Add Gateway Auth
If using HTTP gateway:
// Add auth to HTTP gateway
http.Handle("/", gateway.Handler(
gateway.WithAuth(authProvider),
))
4. Service-to-Service Auth
Services calling other services:
// Service A calls Service B with its own token
client := micro.NewService(
micro.WrapClient(
authWrapper.FromContext(authProvider),
),
)
5. Token Refresh
// Check if token is expiring
if time.Until(token.Expiry) < 5*time.Minute {
token, _ = authProvider.Token(auth.WithToken(token.RefreshToken))
}
Troubleshooting
Error: "missing authorization token"
- Cause: Client didn't send Authorization header
- Fix: Wrap client with
authWrapper.FromToken(token)
Error: "invalid token"
- Cause: Token is expired or malformed
- Fix: Generate a new token
Error: "access denied"
- Cause: Account doesn't have required permissions
- Fix: Check authorization rules with
rules.List()
Error: "token verification failed"
- Cause: Server can't verify token (wrong keys, expired, etc.)
- Fix: Ensure server and client use same auth provider
Next Steps
- Read the Auth Documentation
- Explore JWT Auth
- Try Custom Auth Provider
- See Multi-Tenant Auth
Summary
The auth wrappers make it easy to:
- Protect services: Add
WrapHandler(AuthHandler(...)) - Add authentication to clients: Add
WrapClient(FromToken(...)) - Control access: Define rules with
rules.Grant() - Access account info: Use
auth.AccountFromContext(ctx)
That's it! Your microservices now have enterprise-grade authentication and authorization.