package interceptor import ( "context" "strings" authpb "datarush/pkg/api/auth" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" ) type contextKey string const ( UserIDKey contextKey = "user_id" authHeader = "authorization" bearerScheme = "bearer" ) type AuthInterceptor struct { authClient authpb.AuthServiceClient } func NewAuthInterceptor(authClient authpb.AuthServiceClient) *AuthInterceptor { return &AuthInterceptor{authClient: authClient} } func (i *AuthInterceptor) Unary() grpc.UnaryServerInterceptor { return func( ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, ) (interface{}, error) { md, ok := metadata.FromIncomingContext(ctx) if !ok { return nil, status.Error(codes.Unauthenticated, "metadata is not provided") } authHeaders := md.Get(authHeader) if len(authHeaders) == 0 { return nil, status.Error(codes.Unauthenticated, "authorization token is not provided") } header := authHeaders[0] parts := strings.Split(header, " ") if len(parts) != 2 || !strings.EqualFold(parts[0], bearerScheme) { return nil, status.Errorf(codes.Unauthenticated, "invalid authorization header format") } token := parts[1] validateResp, err := i.authClient.ValidateToken(ctx, &authpb.ValidateTokenRequest{ Token: token, }) if err != nil { return nil, status.Errorf(codes.Unauthenticated, "failed to validate token: %v", err) } newCtx := context.WithValue(ctx, UserIDKey, validateResp.GetUserId()) return handler(newCtx, req) } }