Files
go-usertoken/grpc.go
T
konradandCursor b344df5c1b 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>
2026-09-28 17:37:08 +02:00

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
}