Portal Community

IPassportClient Interface

public interface IPassportClient
{
    Task<PassportUser?> LookupUserAsync(
        UserLookupRequest request,
        CancellationToken ct = default);

    Task<IReadOnlyList<PassportUser>> GetRoleMembersAsync(
        RoleMembersRequest request,
        CancellationToken ct = default);

    Task<bool> CheckPermissionAsync(
        PermissionCheckRequest request,
        CancellationToken ct = default);

    Task<PassportUser?> GetUserByIdAsync(
        string userId,
        string tenantId,
        CancellationToken ct = default);
}

public record UserLookupRequest
{
    public string LookupBy { get; init; } = default!;   // email | employeeId | username | userId
    public string Value { get; init; } = default!;
    public bool IncludeRoles { get; init; }
    public string TenantId { get; init; } = default!;
}

public record PassportUser
{
    public string UserId { get; init; } = default!;
    public string Email { get; init; } = default!;
    public string DisplayName { get; init; } = default!;
    public string? Username { get; init; }
    public string? EmployeeId { get; init; }
    public bool IsActive { get; init; }
    public string[] Roles { get; init; } = [];
    public string? ManagerId { get; init; }
    public string? Department { get; init; }
}

Caching Layer

The CachedPassportClient decorator wraps HttpPassportClient and caches responses for 60 seconds per execution to reduce Passport API calls:

// DI registration
services.AddHttpClient<IPassportClient, HttpPassportClient>();
services.Decorate<IPassportClient, CachedPassportClient>();
// CachedPassportClient uses IMemoryCache with sliding 60-second expiry per (tenantId, lookupKey)

DI Registration in Executors

// Executors inject IPassportClient via constructor
public class UserLookupExecutor : BaseNodeExecutor<UserLookupConfig>
{
    private readonly IPassportClient _passport;
    private readonly IExpressionEvaluator _evaluator;

    public UserLookupExecutor(IPassportClient passport, IExpressionEvaluator evaluator)
    {
        _passport = passport;
        _evaluator = evaluator;
    }
    // ...
}
Custom executors: If you build a custom node that needs identity data, inject IPassportClient directly — do not call Passport HTTP endpoints yourself. This ensures you benefit from tenant scoping enforcement, caching, and circuit breaker protection built into the client implementation.