Implementing Authorization

1. Implementing Role-Based Access Control

Example: Role check in interceptor

methodRoles := map[string][]string{
    "/user.v1.UserService/DeleteUser": {"admin"},
}
func RBAC(ctx context.Context, req any, info *grpc.UnaryServerInfo,
    h grpc.UnaryHandler) (any, error) {
    claims := ctx.Value(claimsKey{}).(jwt.MapClaims)
    role, _ := claims["role"].(string)
    if need, ok := methodRoles[info.FullMethod]; ok && !slices.Contains(need, role) {
        return nil, status.Error(codes.PermissionDenied, "forbidden")
    }
    return h(ctx, req)
}
FieldDetail
Source of rolesJWT claim, DB lookup, IDP
Method → role mapStatic config or annotation-driven

2. Implementing Attribute-Based Access Control

AttributeSource
SubjectJWT claims (user id, dept, clearance)
ResourceRequest fields (owner_id, tenant_id)
ActionMethod name
EnvironmentTime, IP, region

3. Creating Authorization Interceptor

PatternDetail
Annotation-drivenRead custom method options at startup, build policy map
Policy engineOPA / Cedar evaluation per call
Cache decisionsKey on (subject, method, resource)

4. Defining Permission Policies

Example: OPA Rego policy

package grpc.authz
default allow := false
allow if {
  input.method == "/order.v1.OrderService/GetOrder"
  input.claims.sub == input.request.user_id
}

5. Using Open Policy Agent

ModeDetail
SidecarOPA running as HTTP service; query per RPC
Embedded (Go SDK)Eval Rego in-process
Envoy ext_authzOPA-Envoy plugin for service mesh

6. Implementing Method-Level Authorization

MechanismDetail
Custom proto optionoption (auth.require) = "orders.read";
Read at runtimeVia proto reflection
Default-denyMissing annotation → deny

7. Handling Authorization Errors

ScenarioStatus
Missing tokenUnauthenticated (16)
Invalid tokenUnauthenticated (16)
Insufficient privilegePermissionDenied (7)
Resource not visibleNotFound (5) to avoid leaking existence

8. Using Claims from JWT

Example: Read claims from ctx

claims := ctx.Value(claimsKey{}).(jwt.MapClaims)
sub := claims["sub"].(string)
scopes := strings.Fields(claims["scope"].(string))

9. Implementing Resource-Based Access

PatternDetail
Ownership checkCompare claim.sub to resource.owner_id
Tenant isolationCompare tenant_id from claim & request
ACL lookupPer-resource permissions in DB / Zanzibar-style

10. Auditing Authorization Decisions

FieldLog
subjectUser id / service account
methodFull RPC name
resourceTarget id
decisionallow / deny + reason
trace_idCorrelate with request