Avnology ID
SDKsGo SDKGuides

gRPC Interceptors

Authenticate and authorize gRPC requests using the Go SDK.

gRPC Interceptors

Protect gRPC services with unary and streaming interceptors for token validation and permission checks.

Unary interceptor

package interceptor

import (
    "context"
    "strings"

    avnologyid "github.com/avnology/sdk-go"
    "google.golang.org/grpc"
    "google.golang.org/grpc/codes"
    "google.golang.org/grpc/metadata"
    "google.golang.org/grpc/status"
)

func AuthUnaryInterceptor(client *avnologyid.Client) grpc.UnaryServerInterceptor {
    return func(
        ctx context.Context,
        req any,
        info *grpc.UnaryServerInfo,
        handler grpc.UnaryHandler,
    ) (any, error) {
        md, ok := metadata.FromIncomingContext(ctx)
        if !ok {
            return nil, status.Error(codes.Unauthenticated, "missing metadata")
        }

        authValues := md.Get("authorization")
        if len(authValues) == 0 || !strings.HasPrefix(authValues[0], "Bearer ") {
            return nil, status.Error(codes.Unauthenticated, "missing bearer token")
        }

        token := strings.TrimPrefix(authValues[0], "Bearer ")
        result, err := client.OAuth.IntrospectToken(ctx, &avnologyid.IntrospectTokenParams{
            Token: token,
        })
        if err != nil || !result.Active {
            return nil, status.Error(codes.Unauthenticated, "invalid token")
        }

        ctx = context.WithValue(ctx, "userID", result.Sub)
        ctx = context.WithValue(ctx, "scopes", strings.Split(result.Scope, " "))

        return handler(ctx, req)
    }
}

Using the interceptor

server := grpc.NewServer(
    grpc.UnaryInterceptor(interceptor.AuthUnaryInterceptor(avnologyClient)),
)

See also

On this page