Check the same user token on gRPC as on HTTP.
Microservices can forward the raw bearer from the interceptor context. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
package usertoken
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// UnaryServerInterceptor requires a bearer on every RPC.
|
||||
// Success stores the Caller and the raw JWT on the handler context, same as
|
||||
// [Auth.Middleware]. Native clients send metadata key "authorization".
|
||||
// The HTTP gateway's forwarded header is "grpcgateway-authorization".
|
||||
func (a *Auth) UnaryServerInterceptor() grpc.UnaryServerInterceptor {
|
||||
return func(ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
|
||||
raw, ok := bearerFromMetadata(ctx)
|
||||
if !ok {
|
||||
return nil, status.Error(codes.Unauthenticated, "unauthorized")
|
||||
}
|
||||
caller, err := a.Verify(ctx, raw)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Unauthenticated, "unauthorized")
|
||||
}
|
||||
return handler(withAuth(ctx, caller, raw), req)
|
||||
}
|
||||
}
|
||||
|
||||
func bearerFromMetadata(ctx context.Context) (string, bool) {
|
||||
md, ok := metadata.FromIncomingContext(ctx)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
for _, key := range []string{"authorization", "grpcgateway-authorization"} {
|
||||
vals := md.Get(key)
|
||||
if len(vals) == 0 {
|
||||
continue
|
||||
}
|
||||
if raw, ok := bearerToken(vals[0]); ok {
|
||||
return raw, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
Reference in New Issue
Block a user