mirror of
https://github.com/go-micro/go-micro.git
synced 2026-04-30 19:15:24 +02:00
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.