Microservices can forward the raw bearer from the interceptor context. Co-authored-by: Cursor <cursoragent@cursor.com>
46 lines
1.3 KiB
Go
46 lines
1.3 KiB
Go
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
|
|
}
|