Workload Authorization Grant flow
An Agent Platform's grant, traded at its WAG issuer in the enterprise's Workload IdP (ZipIdP) for the issuer's own grant, traded at an application for an access token.
---
title: Workload Authorization Grant, chained through the enterprise IdP (draft-carleton-workload-authz-grant-01)
---
sequenceDiagram
autonumber
actor IdPAdmin as Enterprise IdP admin
participant AP as Agent Platform<br/>(creates agents, signs their grants)
participant Agent
participant IdP as Enterprise Workload IdP<br/>(ZipIdP, WAG issuer /wag/{slug})
actor AppAdmin as Application admin
participant AS as Application AS<br/>(workload-api /token)
participant API as Application API<br/>(/api/*)
rect rgba(128, 128, 128, 0.12)
Note over IdPAdmin, API: One-time setup (nothing about individual agents is exchanged)
AP-->>IdPAdmin: Agent Platform's issuer identifier and public JWKS
IdPAdmin->>IdP: Create a WAG issuer for the Agent Platform in /admin/wag,<br/>registering its iss, JWKS or jwks_uri,<br/>and claims to pass through (e.g. team)
IdP-->>IdPAdmin: The WAG issuer's identifier https://host/wag/{slug}<br/>plus metadata and JWKS URLs
AppAdmin->>AS: Register the WAG issuer in config.json:<br/>issuer, keys from metadata, scopes, claim_scopes
AS->>IdP: GET /.well-known/oauth-authorization-server/wag/{slug}
IdP-->>AS: issuer (must match exactly), jwks_uri
AS->>IdP: GET /wag/{slug}/jwks
IdP-->>AS: The WAG issuer's public keys (cached 1h)
end
rect rgba(128, 128, 128, 0.06)
Note over AP, Agent: Per agent: the Agent Platform creates an agent and names it.<br/>Nothing is sent to the IdP, the application's AS or its API.
end
rect rgba(80, 140, 255, 0.10)
Note over AP, API: Per access
Agent->>AP: Ask for a grant
AP-->>Agent: Agent Platform grant, signed with the Agent Platform's key<br/>iss = Agent Platform, sub = agent id at the Platform<br/>aud = the WAG issuer, exp, iat, jti, claims
Agent->>IdP: POST /wag/{slug}/token (token exchange)<br/>subject_token = Agent Platform grant<br/>subject_token_type and requested_token_type = token-type:wag<br/>audience = application AS issuer<br/>resource and scope (optional)
activate IdP
Note right of IdP: The WAG issuer checks iss is its Agent Platform<br/>Verify with that Platform's keys only<br/>Check aud, exp, iat, jti (single use)
Note right of IdP: First sight of this sub?<br/>Record agent with new sub agent_{random},<br/>never reassigned
Note right of IdP: The WAG issuer signs its grant with its current key<br/>iss = the WAG issuer, sub = agent_..., aud = application AS, resource if requested<br/>exp capped near the Agent Platform grant's exp<br/>plus passthrough and static claims
IdP-->>Agent: access_token = the WAG issuer's grant<br/>issued_token_type token-type:wag, token_type N_A
deactivate IdP
Agent->>AS: POST /token<br/>grant_type=jwt-bearer, assertion=the WAG issuer's grant<br/>resource=AS/api (optional)
activate AS
Note right of AS: Match iss (and tenant claim) to one registered WAG issuer<br/>Verify with that issuer's keys only<br/>(unknown kid: refetch its JWKS once)
Note right of AS: Check aud = this issuer, exp, iat, sub<br/>jti single use per issuer<br/>Record agent under (issuer, sub)
Note right of AS: Scopes = requested within policy<br/>(base scopes plus claim_scopes, e.g. team=core)
AS-->>Agent: Access token (at+jwt), Bearer<br/>aud = API, client_id = the WAG issuer<br/>no refresh token
deactivate AS
Agent->>API: GET /api/issues<br/>Authorization: Bearer access token
activate API
Note right of API: Verify at+jwt signature, iss, aud, exp<br/>Check scope issues:read
API-->>Agent: 200 issues
deactivate API
Agent->>API: POST /api/issues
alt Token has issues:write
API-->>Agent: 200 issue created
else Scope missing
API-->>Agent: 403 insufficient_scope<br/>WWW-Authenticate names issues:write
end
end
rect rgba(255, 90, 90, 0.08)
Note over Agent, AS: Refusals: error_description says who must act (section 7)
alt Agent Platform not the one this issuer trusts, or agent disabled
IdP-->>Agent: 400 invalid_grant (enterprise IdP admin must act)
else WAG issuer not registered at the application, or new-agent cap reached
AS-->>Agent: 400 invalid_grant (application admin must act)
else Bad signature, wrong aud, expired, or replayed grant
AS-->>Agent: 400 invalid_grant (issuer of the grant must act)
else Scope outside policy
AS-->>Agent: 400 invalid_scope (application admin must act)
end
end
Mermaid source
---
title: Workload Authorization Grant, chained through the enterprise IdP (draft-carleton-workload-authz-grant-01)
---
sequenceDiagram
autonumber
actor IdPAdmin as Enterprise IdP admin
participant AP as Agent Platform<br/>(creates agents, signs their grants)
participant Agent
participant IdP as Enterprise Workload IdP<br/>(ZipIdP, WAG issuer /wag/{slug})
actor AppAdmin as Application admin
participant AS as Application AS<br/>(workload-api /token)
participant API as Application API<br/>(/api/*)
rect rgba(128, 128, 128, 0.12)
Note over IdPAdmin, API: One-time setup (nothing about individual agents is exchanged)
AP-->>IdPAdmin: Agent Platform's issuer identifier and public JWKS
IdPAdmin->>IdP: Create a WAG issuer for the Agent Platform in /admin/wag,<br/>registering its iss, JWKS or jwks_uri,<br/>and claims to pass through (e.g. team)
IdP-->>IdPAdmin: The WAG issuer's identifier https://host/wag/{slug}<br/>plus metadata and JWKS URLs
AppAdmin->>AS: Register the WAG issuer in config.json:<br/>issuer, keys from metadata, scopes, claim_scopes
AS->>IdP: GET /.well-known/oauth-authorization-server/wag/{slug}
IdP-->>AS: issuer (must match exactly), jwks_uri
AS->>IdP: GET /wag/{slug}/jwks
IdP-->>AS: The WAG issuer's public keys (cached 1h)
end
rect rgba(128, 128, 128, 0.06)
Note over AP, Agent: Per agent: the Agent Platform creates an agent and names it.<br/>Nothing is sent to the IdP, the application's AS or its API.
end
rect rgba(80, 140, 255, 0.10)
Note over AP, API: Per access
Agent->>AP: Ask for a grant
AP-->>Agent: Agent Platform grant, signed with the Agent Platform's key<br/>iss = Agent Platform, sub = agent id at the Platform<br/>aud = the WAG issuer, exp, iat, jti, claims
Agent->>IdP: POST /wag/{slug}/token (token exchange)<br/>subject_token = Agent Platform grant<br/>subject_token_type and requested_token_type = token-type:wag<br/>audience = application AS issuer<br/>resource and scope (optional)
activate IdP
Note right of IdP: The WAG issuer checks iss is its Agent Platform<br/>Verify with that Platform's keys only<br/>Check aud, exp, iat, jti (single use)
Note right of IdP: First sight of this sub?<br/>Record agent with new sub agent_{random},<br/>never reassigned
Note right of IdP: The WAG issuer signs its grant with its current key<br/>iss = the WAG issuer, sub = agent_..., aud = application AS, resource if requested<br/>exp capped near the Agent Platform grant's exp<br/>plus passthrough and static claims
IdP-->>Agent: access_token = the WAG issuer's grant<br/>issued_token_type token-type:wag, token_type N_A
deactivate IdP
Agent->>AS: POST /token<br/>grant_type=jwt-bearer, assertion=the WAG issuer's grant<br/>resource=AS/api (optional)
activate AS
Note right of AS: Match iss (and tenant claim) to one registered WAG issuer<br/>Verify with that issuer's keys only<br/>(unknown kid: refetch its JWKS once)
Note right of AS: Check aud = this issuer, exp, iat, sub<br/>jti single use per issuer<br/>Record agent under (issuer, sub)
Note right of AS: Scopes = requested within policy<br/>(base scopes plus claim_scopes, e.g. team=core)
AS-->>Agent: Access token (at+jwt), Bearer<br/>aud = API, client_id = the WAG issuer<br/>no refresh token
deactivate AS
Agent->>API: GET /api/issues<br/>Authorization: Bearer access token
activate API
Note right of API: Verify at+jwt signature, iss, aud, exp<br/>Check scope issues:read
API-->>Agent: 200 issues
deactivate API
Agent->>API: POST /api/issues
alt Token has issues:write
API-->>Agent: 200 issue created
else Scope missing
API-->>Agent: 403 insufficient_scope<br/>WWW-Authenticate names issues:write
end
end
rect rgba(255, 90, 90, 0.08)
Note over Agent, AS: Refusals: error_description says who must act (section 7)
alt Agent Platform not the one this issuer trusts, or agent disabled
IdP-->>Agent: 400 invalid_grant (enterprise IdP admin must act)
else WAG issuer not registered at the application, or new-agent cap reached
AS-->>Agent: 400 invalid_grant (application admin must act)
else Bad signature, wrong aud, expired, or replayed grant
AS-->>Agent: 400 invalid_grant (issuer of the grant must act)
else Scope outside policy
AS-->>Agent: 400 invalid_scope (application admin must act)
end
end