PasskeyBridge —

Compliance & Privacy · 2026-03-29

SOC 2 Type II for Identity APIs: The Audit Controls Few Will Tell You About

By J. W. Bouckaert

SOC 2 Type II for Identity APIs: The Audit Controls Few Will Tell You About

SOC 2 Type II for identity-layer APIs

Most SOC 2 guidance stops at the Trust Services Criteria categories: Security, Availability, Processing Integrity, Confidentiality and Privacy. Those categories apply to identity-layer APIs, but they say little about the controls such an API needs. An identity platform issues cryptographic assertions about who a person is, whether their device or number shows signs of compromise, and whether an AI agent is authorized to act for them.

A SOC 2 Type I report covers the design of controls at a point in time. A Type II report covers whether those controls operated effectively over an observation period, commonly 3 to 12 months. For identity APIs that process carrier signals, issue verifiable credentials and run passkey ceremonies, the operating evidence is what a reader of the report relies on.

This article covers five control areas for identity-layer APIs and the evidence an auditor can ask for in each.

Five control areas for identity APIs

SOC 2 examinations use the AICPA Trust Services Criteria (TSC). The criteria are written in general terms, so the service organization decides how to meet them. For an identity API, five areas carry most of the weight:

Control areaTSC mappingIdentity API requirement
Tamper-evident audit loggingCC7.2, CC7.3API calls, mutations and administrative actions recorded where clients cannot change them
Key managementCC6.1Keys created, stored, rotated and retired under a documented procedure
Tenant isolationCC6.1, CC6.3Access to one tenant's data limited to that tenant, enforced below the application where possible
Credential lifecycleCC6.2, CC6.3Credentials issued with a recorded scope, with defined validity and a revocation path
Access scope enforcementCC6.1, CC6.3API keys, agent delegates and user sessions limited to the operations they need

Each of these areas is easier to build in from the start than to retrofit.

Control 1: Tamper-evident audit logging

Auditor expectations

CC7.2 covers monitoring system components for anomalies and analyzing them to determine whether they are security events. CC7.3 covers evaluating security events to determine whether they are incidents. For an identity API, that means signal ingest, credential issuance, key rotation, agent delegation and administrative changes should each produce an audit record.

Audit records should be append-only for every client role. No tenant user or API key should be able to modify or delete an entry after it is written.

In practice

An audit log schema for an identity API commonly captures these fields:

FieldTypePurpose
tenant_idUUIDTenant isolation for multi-tenant platforms
actor_idUUID (nullable)The authenticated user, API key or system process
actor_typeEnumFor example user, system, api_key, agent_delegate
actor_ip_hashTextKeyed HMAC-SHA-256 digest of the source IP under a server-held pepper; the raw address is never stored
actionTextMachine-readable action identifier, such as key.rotate or credential.issue
resource_typeTextThe resource acted on, such as api_key
resource_idTextSpecific resource identifier
changesJSONBBefore and after state for mutations
resultEnumFor example success, failure, denied
error_messageTextFailure reason, sanitized, with no stack traces
created_atTimestamptzServer-side timestamp

created_at should be set by the server. A client-supplied timestamp lets anyone holding a stolen API key backdate their activity.

Enforcing append-only records

Two database mechanisms keep client roles from changing audit rows:

  1. Grants: client roles get no UPDATE or DELETE privilege on the audit table, enforced at the PostgreSQL role level.
  1. Row-level security: policies on the audit table allow SELECT to the roles that may read it and define no UPDATE or DELETE policy.

A database owner or service role can still bypass both. Hash-chaining each row to the previous one, and signing periodic checkpoints of the chain, makes a change by such a role detectable. An auditor can ask for the role configuration and for the output of the chain verification.

Control 2: Key management

Auditor expectations

The CC6.1 points of focus include protecting encryption keys during generation, storage, use and destruction. An auditor will look for a documented procedure for each key type and evidence that the procedure was followed during the period.

Rotation design

Key types in an identity API differ in how they can rotate:

Key typeRotation approach
Tenant API keysIssue a new key, move clients to it, then revoke the old key
Credential signing keysPublish the new public key before signing with it, and keep the old public key available for as long as credentials signed with it must verify
Session keysEphemeral per session, destroyed on teardown
Keys derived from a master secretRotating the master changes every derived key, so credentials signed before the change stop verifying unless the old keys are kept

When a signing key rotates, verifiers must still be able to check what the old key signed. A rotation that withdraws the old public key at once causes verification failures for anything signed before the change.

Evidence the auditor reviews

  1. Rotation records: timestamped audit entries showing when each key was rotated, by whom, and whether the rotation was scheduled or manual.
  1. Procedure: the documented intervals and overlap periods, and the code or configuration that implements them.
  1. Failure handling: evidence that a failed rotation, such as a write error during the key swap, cannot leave the system with no active key.

Control 3: Tenant isolation

Auditor expectations

For a multi-tenant identity API, CC6.1 and CC6.3 cover limiting access to one tenant's data to the users authorized for it. Enforcement below the application layer reduces the impact of an application bug.

Limits of application-layer isolation

A common pattern filters tenant data in application code:

// Application-layer isolation
const events = await db.query(
  "SELECT * FROM events WHERE tenant_id = $1",
  [currentTenantId]
);

This holds until a developer forgets the WHERE clause, a new endpoint skips the middleware, or an ORM generates an unfiltered query. One missing filter can expose every tenant's data.

Database-layer enforcement

PostgreSQL row-level security (RLS) filters every query against a protected table for the roles the policy covers, whatever the application sends. An example policy that ties rows to the tenants a signed-in user belongs to:

-- Database-layer tenant isolation
ALTER TABLE events ENABLE ROW LEVEL SECURITY;

CREATE POLICY tenant_members_read ON events
  FOR SELECT
  TO authenticated
  USING (tenant_id IN (
    SELECT tenant_id FROM tenant_members WHERE user_id = current_user_id()
  ));

With this policy, a query from a signed-in user without a WHERE tenant_id = ... clause returns only rows for that user's tenants. Server code that runs as a role which bypasses RLS still needs its own tenant filter, and that filter needs tests.

Isolation verification

An isolation test can:

  1. Authenticate as a user of Tenant A
  2. Run an unfiltered SELECT on a tenant-scoped table
  3. Confirm only Tenant A's rows come back
  4. Attempt an UPDATE on a Tenant B row by ID
  5. Confirm zero rows change

Control 4: Credential lifecycle management

Auditor expectations

CC6.2 covers registering and authorizing users before issuing credentials, and removing credentials when access is no longer authorized. CC6.3 covers authorizing, modifying and removing access. For identity APIs, credentials include API keys, verifiable credentials, cached proofs and agent delegation tokens.

Each credential type needs four lifecycle properties:

PropertyRequirement
IssuanceRecorded in the audit log with issuer, scope and expiry
ExpirationA defined maximum validity, or a documented reason for none
RevocationA single API call or dashboard action, with the time it takes effect documented
Re-attestationTriggered by risk signals such as a SIM swap or a key compromise

Time-bounded credentials

SOC 2 does not set expiration periods. The organization sets them in its own policy, and the auditor tests whether the system followed that policy during the period. A credential with no expiry needs a documented compensating control, such as periodic review and revocation on offboarding.

Revocation reach

Revocation has to reach every component that accepts the credential:

  • The API layer, which rejects requests made with a revoked key
  • The credential status endpoint, which returns the revoked status in its status list
  • The agent trust engine, which deactivates delegation tokens
  • The cached proof store, which marks proofs invalid

A component that keeps accepting a revoked credential is a gap an auditor can find by testing it.

Control 5: Access scope enforcement

Auditor expectations

CC6.1 covers logical access security over protected information assets. For identity APIs, API keys, user sessions and agent delegates should each be limited to the operations they need.

Scoped API keys

An identity API key should carry scopes, and each endpoint should check for its scope. PasskeyBridge API keys carry scopes such as these:

ScopeOperations permitted
ingestSubmit signals to the ingest endpoint
events, metricsRead the tenant's Prometheus-format metrics export
vc_issueIssue credentials and create OID4VCI offers
vc_verifyVerify presentations and build OpenID4VP requests
vc_revokeRevoke, suspend and reinstate credentials
spatialSubmit spatially bound attestation data
scimSCIM provisioning
okta_hooksOkta event hook ingestion

A request whose key lacks the endpoint's scope is refused with HTTP 403 and the reason missing-scope. A key scoped only to ingest cannot issue credentials.

Agent scope narrowing

Agent delegates add a second layer. In PasskeyBridge, a tenant admin creates a delegate with a list of scopes, and every verify call checks the requested scope against that list. Each delegate also carries a trust score that falls on signals such as velocity spikes, error bursts and scope violations:

Trust 0.7 or above   -> full delegated scopes
Trust 0.4 to 0.7     -> read-only scopes
Trust floor to 0.4   -> verify only
Below the floor      -> delegate deactivated (default floor 0.2)

The original scope list is kept, and the time and reason of each narrowing are recorded with an audit entry. A tenant can set its own thresholds.

SOC 2 does not mention agents. A control like this is evidence that access changes with risk signals between manual access reviews.

The observation period

In a Type II examination, the auditor tests how controls operated during the period through samples of logs, rotation records, access changes and credential events.

  1. Audit logs must cover the period. Logs deleted before the examination ends cannot serve as evidence.
  1. Rotations must follow the stated schedule. A policy of rotating every 90 days, with no rotation in 180 days, is an exception.
  1. Isolation failures get reported. An incident of cross-tenant exposure during the period can appear in the report even after it is fixed.
  1. Expirations must be enforced. A credential still accepted after its expires_at is a failed lifecycle control.

PasskeyBridge's audit log

PasskeyBridge's audit log records the fields in the table above, with additional actor types and results. Its row-level security allows tenant admins to read their own tenant's rows and gives client roles no write path. Each row is hash-chained, and the chain is checkpointed every five minutes with HMAC-SHA-256 and an ML-DSA-65 signature, anchored to the latest NIST Randomness Beacon pulse. The one sanctioned change to chained rows today, the 90-day retention purge of events, is written to the chain as an amendment record, and chain verification reports any other change as tampering.

PasskeyBridge is preparing for SOC 2 and does not hold a SOC 2 report.

Consequences for your identity stack

If you are building or evaluating an identity API, treat these five areas as design requirements. Moving from a mutable log to an append-only one takes a migration. Moving from application-layer filtering to database-enforced isolation takes changes across the data access layer.

Further reading

Start free · Test the API