PE
Protocol Explorer
Actor Profile

OAuth Actor Profile — Service-to-Service Delegation

Same-domain service-to-service delegation (Appendix A of draft-mcguinness-oauth-actor-profile-00). A payroll batch processor acts on behalf of payroll administrator 'Pat' to call the Payroll API. The Payroll API then exchanges its inbound access token for a Transaction Token at the Audit TTS to write an audit record — preserving the inbound delegation chain by nesting the prior actor beneath a new outermost `act` claim. This is the cleanest demonstration of how the actor profile transforms a single-hop `act` object into a multi-hop nested delegation chain across one Token Exchange hop.

Payroll Batch ProcessorPayroll APIAudit TTSAudit Service1POST /payroll/run + AT2002Token Exchange → TxToken3POST /audit + TxToken
POST https://services.example.com/payroll-api/runs200

The Payroll Batch Processor presents an access token issued earlier by the Enterprise AS. The token's `sub` identifies the payroll administrator (Pat) — the human whose authorization is being exercised — while the single-hop `act` object identifies the batch processor as the service exercising that authorization. The top-level `cnf.jkt` binds the token to the batch processor's key (SvcJKT), demonstrated via the DPoP proof on this request.

This is a single-hop actor object: `act` is present but contains no nested `act`. There has been exactly one delegation hop so far.

`client_id` (`payroll-batch-client`) identifies the OAuth client registration. `act.sub` identifies the acting service via its workload URI. These can be different and serve different purposes — the spec says `act.sub` is the authoritative delegated-actor identifier.

`sub_profile: "user"` and `act.sub_profile: "service"` tell the resource server what kind of entity each principal is. The Payroll API must check both the (sub, act.sub) pair to authorize the operation.

Appendix A §A.2 — `sub` identifies the payroll administrator while `act.sub` identifies the service exercising that administrator's authorization.

The token is sender-constrained via `cnf.jkt` (RFC 9449 DPoP). The Payroll API verifies the DPoP proof presented on this request matches `SvcJKT-123`.

1 / 3
speed

Step 1: POST /payroll/run + AT

Request / response
POSThttps://services.example.com/payroll-api/runs
AuthorizationOAuth?

Bearer <payroll-access-token>

DPoP

<SvcJKT-proof>

Content-Type?

application/json

Host

services.example.com

Body
{
  "period": "2026-03",
  "employees": "all-active"
}
Access Token (single-hop actor)at+jwt
Header
{
"alg":"RS256",
"typ"?:"at+jwt",
"kid":"as-ent-2026"
}
Payload
{
"iss"?:"https://as.example.com",
"sub"?:"https://idp.example.com/users/pat",
"sub_profile":"user",
"client_id":"payroll-batch-client",
"aud"?:"https://services.example.com/payroll-api",
"scope"?:"payroll:run",
"cnf"?:{
"jkt":"SvcJKT-123"
}
,
"act"?:{
"sub"?:"https://services.example.com/payroll-batch",
"iss"?:"https://as.example.com",
"sub_profile":"service"
}
}
sig: SIGNATURE_PAYROLL_AT