gRPC Authorization and Roles
Authentication answers the question "Who are you?" Authorization answers the question "What may you do?" A service can know exactly who calls it and still need rules that limit each caller. Roles give those rules a simple, manageable shape.
The Hotel Key Card Analogy
A hotel verifies your identity at check in. The front desk then hands you a key card. The card opens your room and the gym, but it never opens the manager's office. Staff cards open more doors. Authorization works like those card permissions.
Guest card: Room 204 ✔ Gym ✔ Manager office ✖
Staff card: Room 204 ✔ Gym ✔ Storage room ✔ Manager office ✖
Manager card: Every door ✔
Two Status Codes
| Code | Meaning | Example |
|---|---|---|
| UNAUTHENTICATED | The caller proved no identity | Token missing or expired |
| PERMISSION_DENIED | The caller has an identity but lacks rights | A customer calls an admin method |
Return the correct code. Clients react differently to each. UNAUTHENTICATED prompts a new login. PERMISSION_DENIED tells the user to request access.
Role Based Access Control
Role based access control, called RBAC, assigns permissions to roles and roles to users. Managing three roles costs far less effort than managing thousands of individual users.
User Asha ──▶ Role: support ──▶ Permissions: GetOrder, RefundOrder
User Ravi ──▶ Role: admin ──▶ Permissions: GetOrder, RefundOrder, DeleteOrder
User Meena ─▶ Role: customer ─▶ Permissions: GetOrder
Where the Role Comes From
A trusted earlier step extracts the role and places it in the context. An authentication interceptor validates the token, reads the role claim, and stores the result. The authorization step then reads from the context and never trusts raw request fields.
Authorization Interceptor
One interceptor can guard every method through a table that maps method names to allowed roles.
var methodRoles = map[string][]string{
"/shop.OrderService/GetOrder": {"customer", "support", "admin"},
"/shop.OrderService/RefundOrder": {"support", "admin"},
"/shop.OrderService/DeleteOrder": {"admin"},
}
func authzInterceptor(ctx context.Context, req interface{},
info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
allowed, found := methodRoles[info.FullMethod]
if !found {
return nil, status.Error(codes.PermissionDenied, "method not allowed")
}
role, ok := roleFromContext(ctx)
if !ok {
return nil, status.Error(codes.Unauthenticated, "identity required")
}
if !contains(allowed, role) {
return nil, status.Error(codes.PermissionDenied, "role not permitted")
}
return handler(ctx, req)
}
The default behavior matters: a method missing from the table gets denied. Deny by default protects new methods until someone grants access deliberately.
Resource Level Checks
Roles alone fall short in many cases. A customer may read orders, yet only their own orders. Method level rules pass the call through. The handler then compares the order owner with the caller identity.
func (s *server) GetOrder(ctx context.Context, req *pb.GetOrderRequest) (*pb.Order, error) {
order, err := s.repo.Find(ctx, req.OrderId)
if err != nil {
return nil, status.Error(codes.NotFound, "order not found")
}
caller := userIDFromContext(ctx)
if order.OwnerID != caller && !isStaff(ctx) {
return nil, status.Error(codes.NotFound, "order not found")
}
return toProto(order), nil
}
The code returns NOT_FOUND for another person's order. That choice avoids confirming that the order exists.
Two Layers Working Together
Request ─▶ [Interceptor: role allowed for this method?]
│ yes
▼
[Handler: caller owns this resource?]
│ yes
▼
Reply
Design Tips
- Keep the number of roles small and meaningful
- Name roles after job duties, not after people
- Store the permission table in one place
- Test denied cases as carefully as allowed cases
- Log every denial with the caller and method name
Summary
Authorization decides what an identified caller may do. Use RBAC for method level rules, apply deny by default, and add resource checks inside handlers. Return UNAUTHENTICATED for missing identity and PERMISSION_DENIED for missing rights.
