I have a GRPC server with APIs that are authorized like:
func (s *MyServer) MyAPI(ctx context.Context, req MyAPIRequest) (MyAPIResponse, error) {
isAuthorized, err = s.IsAuthorized(ctx, req.UserId, Role.User) // other APIs may use a different authorization function than IsAuthorized
if err != nil {
return nil, err
}
if !isAuthorized {
return nil, status.Error(codes.PermissionDenied, "not authorized")
}
// rest of API code
}
I'd like to know how to:
- Simplify usage of the authorization logic, like an annotation. I'm more familiar with Java where it would be like
@Authorize(ctx = ctx, req = req, role = Role.User)
above the func. - Require authorization checks for APIs, so that builds fail if at least one API is missing authorization. I'm using bazel. Note that not all
func (s *MyServer)
will be APIs.
Here's my idea:
- .
- Create a YAML file with key value pairs of method name to authorization rule. Example is
MyAPI: IsUserIdAuthorizedAsUser
which would translate tos.IsAuthorized(ctx, req.UserId, Role.User)
. - Create an interceptor that looks up authz rule for the request's method name and calls the corresponding authz function.
- Create a YAML file with key value pairs of method name to authorization rule. Example is
- Have a bazel build rule that parses proto files for
rpc
, which are all the API method names, and fails if not all of them are in the rule list. I don't know how to do this yet.
Would appreciate any suggestions on my idea or better ways.
I would use an interceptor (grpc.UnaryInterceptor) to handle the authentication / authorization process. It is similar to the classic spring filter (java world).
You can read about interceptors here: https://shijuvar.medium.com/writing-grpc-interceptors-in-go-bf3e7671fe48
You can easily chain multi interceptors or having interceptor per grpc method.
This below is an interceptor that I wrote some months ago (it uses JWT as auth mechanism). You can use it as example: