Portal Community

Why Not Use User Accounts for Automation?

Using a personal user account for automation creates serious operational and security risks:

Account Lifecycle

When the employee leaves, their account is disabled — breaking all automations that depend on it, often at 2 AM on a Friday.

Password Rotation

User passwords expire. Automations fail silently until someone discovers the expired password in a production incident.

Audit Confusion

Audit logs show "Jane Smith ran 500 payroll jobs at 3 AM". Automations obscure the human actions in security logs.

Excess Permissions

User accounts have all permissions granted for their human role — far more than the automation needs. Violates least privilege.

What Is a Managed Identity?

A managed identity is a Passport principal that represents an automated process or system integration rather than a human user. It has:

IManagedIdentityService

namespace BizFirst.Essentials.Passport.ManagedIdentities;

public interface IManagedIdentityService
{
    Task<ManagedIdentity> CreateAsync(
        CreateManagedIdentityRequest request,
        CancellationToken ct = default);

    Task<ManagedIdentity?> GetAsync(
        Guid managedIdentityId,
        CancellationToken ct = default);

    Task<IReadOnlyList<ManagedIdentity>> ListAsync(
        string tenantId,
        CancellationToken ct = default);

    Task DisableAsync(
        Guid managedIdentityId,
        CancellationToken ct = default);

    Task DeleteAsync(
        Guid managedIdentityId,
        CancellationToken ct = default);
}

public class ManagedIdentity
{
    public required Guid   Id          { get; init; }
    public required string ClientId    { get; init; }  // for OAuth client credentials flow
    public required string TenantId    { get; init; }
    public required string Name        { get; init; }
    public string? Description         { get; init; }
    public bool    IsEnabled           { get; init; } = true;
    public DateTimeOffset CreatedAt    { get; init; }
    public DateTimeOffset? LastUsedAt  { get; init; }
    public IReadOnlyList<string> Roles { get; init; } = [];
}

Authentication Flow

// OAuth 2.0 Client Credentials Flow
POST /passport/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic base64("clientId:clientSecret")

grant_type=client_credentials
&scope=openid%20roles

// Response
{
  "access_token": "eyJhbGciOiJSUzI1NiJ9...",
  "token_type":   "Bearer",
  "expires_in":   3600  // 1 hour
  // No refresh_token — each call uses client credentials
}

// Token payload shows it is a managed identity
{
  "sub":                  "managed-identity-client-id",
  "managed_identity_id":  "managed-identity-guid",
  "is_service_account":   true,
  "tenant_id":            "tenant-abc",
  "roles":                ["payroll-executor"],
  "iss":                  "https://passport.bizfirst.ai",
  "aud":                  "bizfirstgo-api"
}

Key Differences from User Accounts

AspectUser AccountManaged Identity
AuthenticationPassword + optional MFAclientId + clientSecret
SessionLong-lived session cookieNo session — per-call authentication
Token typeAccess + refresh + id tokensAccess token only (no refresh)
Token lifetime15 min access / 7 day refresh1 hour access
MFAOptional or requiredNot applicable
Password expiryYes (configurable)No — secrets have no expiry unless explicitly rotated
Audit attributionHuman name + emailManaged identity name + clientId