Portal Community

CreateManagedIdentityRequest

public class CreateManagedIdentityRequest
{
    public required string Name        { get; init; }  // human-readable name (appears in audit logs)
    public string? Description         { get; init; }  // purpose of this identity
    public required string TenantId    { get; init; }  // must match a valid tenant
    public string[]? InitialRoles      { get; init; }  // role names to assign immediately
    public string[]? Tags              { get; init; }  // for filtering/organization
}

Creating via API

POST /passport/admin/managed-identities
Authorization: Bearer {admin-token}
Content-Type: application/json

{
  "name":        "payroll-scheduler",
  "description": "Runs the monthly payroll workflow on the 25th of each month",
  "tenantId":    "tenant-abc",
  "initialRoles":["payroll-executor"],
  "tags":        ["automation", "payroll", "scheduler"]
}

// Response — SECRET SHOWN ONLY ONCE
{
  "managedIdentityId": "mi-guid-1234",
  "clientId":          "mi-payroll-scheduler-clientid",
  "clientSecret":      "mics_sk_xxxxxxxxxxxxxxxxxxxxxxxx",  // STORE SECURELY
  "name":              "payroll-scheduler",
  "tenantId":          "tenant-abc",
  "createdAt":         "2026-05-25T10:00:00Z"
}
Store the Client Secret Immediately

The clientSecret is shown only once in the creation response. It is stored as a one-way hash in Passport — it cannot be retrieved again. Store it immediately in a secrets manager (Azure Key Vault, AWS Secrets Manager, HashiCorp Vault). If lost, generate a new secret using the credential rotation process.

Naming Conventions

Managed identity names appear directly in audit logs. A well-chosen name makes security investigations straightforward. Follow this convention:

// Good naming — describes function, not the team
"payroll-monthly-scheduler"
"hr-onboarding-integration"
"erp-data-sync-agent"
"slack-notification-sender"
"backup-export-job"

// Poor naming — vague, no context
"service1"
"automation"
"test-mi"
"john-smith-service"  // DO NOT use person names

Listing Managed Identities

GET /passport/admin/managed-identities?tenantId=tenant-abc
Authorization: Bearer {admin-token}

// Response
{
  "managedIdentities": [
    {
      "managedIdentityId": "mi-guid-1234",
      "clientId":          "mi-payroll-scheduler-clientid",
      "name":              "payroll-monthly-scheduler",
      "description":       "Runs the monthly payroll workflow on the 25th",
      "tenantId":          "tenant-abc",
      "isEnabled":         true,
      "createdAt":         "2026-05-25T10:00:00Z",
      "lastUsedAt":        "2026-05-25T10:05:00Z",
      "roles":             ["payroll-executor"],
      "tags":              ["automation", "payroll"]
    }
  ],
  "total": 1
}

Disabling a Managed Identity

// Disable immediately (revokes all active tokens)
POST /passport/admin/managed-identities/{managedIdentityId}/disable
Authorization: Bearer {admin-token}
Content-Type: application/json

{
  "reason": "security-incident",
  "disabledBy": "admin-user-guid"
}

// Re-enable
POST /passport/admin/managed-identities/{managedIdentityId}/enable
Authorization: Bearer {admin-token}

Terraform / Infrastructure-as-Code

# Manage managed identities with Terraform (Passport provider)
resource "bizfirst_managed_identity" "payroll_scheduler" {
  name        = "payroll-monthly-scheduler"
  description = "Runs the monthly payroll workflow"
  tenant_id   = var.tenant_id

  roles = ["payroll-executor"]

  tags = {
    team        = "finance"
    environment = "production"
  }
}

# Store the secret in Azure Key Vault
resource "azurerm_key_vault_secret" "payroll_scheduler_secret" {
  name         = "payroll-scheduler-client-secret"
  value        = bizfirst_managed_identity.payroll_scheduler.client_secret
  key_vault_id = azurerm_key_vault.main.id
}