Skip to content
Agent Identity

Deployment pattern

All patterns

Unattended batch

Batch / cron agentSPIRE / issuerASAPI

Unattended batch / service agent

/patterns/unattended-batch

A cron, a queue worker, a service account with no human on the request. Client credentials and workload identity. Never the password grant. Never a long-lived user refresh token stuffed into the job.

When you see it

Nightly summarization over a corpus the service owns, a pipeline that classifies tickets as itself, a scheduled agent that calls internal APIs with a workload identity. If a human must approve a specific action, that is headless/async (CIBA), not this row.

Actors and trust

  • Service agentWorkload

    Acts as itself. Identified by client_id plus workload identity, not by a user sub.

  • Authorization server (optional)Other

    Issues a client-credentials access token audience-restricted to the API.

  • ResourceResource

    Authorizes a service account / SPIFFE ID. There is no 'on behalf of Alice' unless you moved to an OBO row.

Topology

Batch / cron agentSPIRE / issuerASAPI
  • SPIRE / issuerWorkload identityBatch / cron agent
  • Batch / cron agentclient_credentials (SPIFFE or mTLS client auth)AS
  • Batch / cron agentService-account call; aud = this APIAPI
No user. The job authenticates as itself — client credentials and/or a workload SVID — then calls the API.

Primary

Optional

Do not use

  • Resource Owner Password Credentials

    Never. Removed from OAuth 2.1.

  • Long-lived user refresh token in a cron

    That is someone else's grant, parked in a job. Use client credentials, or CIBA when a human must approve.

  • OpenID Connect Core

    No user on this hop. An ID Token is not an access token.

Why these, and not those

Client credentials (OAuth 2.1) and workload identity (SPIFFE/WIMSE) answer 'which robot is this?' They do not answer 'which human?' — and this row has no human. The password grant is gone (OAuth 2.1 / RFC 9700) and was always the wrong way to let a batch job impersonate someone. A long-lived user refresh token in a cron secret is delegated access with no session, no rotation story, and no way for the user to know the job is still running. If you need a user, use CIBA or an interactive grant at the time of action. AAP and AIMS are draft profiles/BCPs on this shape; treat them as churn.

Related flows

Sequence diagrams, not this topology cut. All flows

Back to the matrix