Repository navigation
Authenticate internal services with JWT #1557
Description
Goal
Enable JWT-based authentication for Scope's internal service calls, so protected
API and evaluation requests require a verified service/job identity instead of
relying on anonymous access.
This is the service-authentication delivery under parent #17. Human project RBAC
belongs to #1300; human CLI login and credential management belong to #1562.
Problem
The existing human authentication path verifies an IdP bearer and resolves an
enrolled Scope user. Internal services do not have an equivalent authenticated
service/job path and must not be enrolled as human users.
On the inspected base implementation, requests without a bearer can fall through
as anonymous. #1532 adds route authorization that rejects those internal callers
when authentication is enabled. That breaks agent registration/startup, worker
content loading, judge criteria loading, and model scanning.
The current auth architecture documentation also understates the internal-caller
inventory. Update it alongside the implementation.
Scope
| Boundary | Required outcome |
|---|---|
| Coding workers → API | Authenticate all content reads and archive downloads; restrict them to the active run/claim and canonical project. |
Coding workers → judge /api/v1/evaluate |
Authenticate evaluation requests and bind downstream criteria authority to that evaluation's authorized run/project. |
| Judge → API | Authenticate criteria and ancestor reads; isolate credentials and caches between evaluations. |
| Agent registration → API | Permit only the required agent and agent-version registration operations. |
| Model scanners → API | Permit only required agent discovery/registration and model synchronization operations. |
Both AKS and authenticated local Docker Compose are required delivery targets.
Other cloud/Kubernetes identity integrations remain extension points, not required
implementations for this issue.
Infrastructure inputs assumed supplied
Consume the external JWT foundation contract: issuer, audiences/purposes,
allowed algorithms and trusted keys, workload bootstrap/acquisition interfaces,
token lifetimes, public trust/rotation, protected transport, and AKS/local
configuration. This issue owns application integration, not infrastructure
research or provisioning.
The external foundation is tracked in
growth-ecosystems/scope-core-infra#150.
Assuming that contract for planning is not a claim that infrastructure is deployed.
Explicitly out of scope
- Report-generator authentication and post-run report-trigger authentication.
These remain separate work; this issue does not claim complete authentication
coverage for report workflows or enable report functionality. - Submitter-rights binding. Removing a submitting user's membership does not, by
itself, revoke an active job's authority in this delivery. - Authentication of unrelated internal-service endpoints, Token Manager, or data
stores. Their credentials must not receive Scope API credentials. - A mandatory service mesh, a general network-encryption rollout, or NetworkPolicy
hardening. Credential transport protection still needs an explicit decision. - Human CLI login, cache storage, refresh, and logout; these belong to
Add CLI sign-in and JWT credential management #1562. Preserve the existing human IdP-token/enrollment and Portal
behavior without forwarding human bearer tokens into jobs. - Scope-managed user PATs/API tokens. Existing
SCOPE_TOKENraw-bearer support
remains supported; it does not become a PAT issuance system.
Required security and lifecycle contract
- Represent service/job callers separately from human users. They must not enter
human enrollment or the human-user access cache. - Authenticate protected operations and enforce explicit route permissions.
Route/OpenAPI metadata alone is not enforcement. Preserve an explicit public
endpoint allowlist; public discovery must not become a credential bypass. - Give registration and scanners named, narrow system-operation permissions,
never platform-admin or unrestricted project-content authority. - Bind worker/judge content authority to a canonical request/run, current claim,
and project. Derive project scope from trusted records, not a caller-supplied
project or user ID. - Verify that the authenticated caller is entitled to the claim. Knowing a
request ID, run ID, claim ID, or worker instance ID is not proof of ownership. - Enforce project isolation for UUID, slug, reference, archive, and derived-resource
lookups. Reject unrelated routes and writes even with a valid credential. - End job authority on completion, cancellation, reaping, or reclaim. Expiry alone
is insufficient. Any reusable cache must preserve that revocation contract. - Support long-running jobs without silently expiring credentials or sharing one
evaluation's bearer/provider/cache with another. - Use a shared async bearer provider for acquisition/renewal with deduplicated
concurrent refresh and bounded transient-failure retry. Do not stack retry
layers or retry permanent authentication/permission failures indefinitely. - Fail closed when credential or live-authority validation cannot be completed.
Distinguish invalid credentials, insufficient authority, and unavailable
dependencies; exact HTTP/retry semantics remain to be specified. - Keep credentials out of URLs, queue payloads, logs, telemetry, snapshots,
agent environments, MCP configurations, and AI-visible tools.
Application decisions required before implementation
| Decision | What remains unanswered |
|---|---|
| Claim ownership trust | Is a service class the trust boundary, or must individual instances be isolated? Who records the trusted binding, and how does issuance/access verify it without accepting self-asserted IDs? |
| Job binding and credential acquisition | Under the supplied JWT contract, how does the application request and validate job authority for its active claim? What prevents one authenticated worker from selecting another claim? Define legacy/unclaimed-record behavior. |
| Judge delegation | How are evaluation requests verified, audiences/delegation constrained, and downstream criteria credentials obtained and renewed? |
| Lifecycle and failures | Which live records are checked, how are renewals deduplicated, and what are outage/error/retry semantics? Are live checks sufficient, or is individual-token revocation needed? |
| RBAC integration | What is the implementation/merge target relative to #1532, which layer consumes verified principals and enforces policy, and what behavior is supported between merges? |
Validate against the supplied issuer/audience/algorithm/key/purpose/claim and
expiry contract; do not derive trusted key URLs from unverified claims. Preserve
verified expiry in the principal/policy integration rather than assuming every
authenticated token is a human IdP credential. Workers never hold signing keys.
Acceptance criteria
- With authentication enabled, Compose startup completes agent/version
registration and non-report workers start; equivalent AKS wiring is verified. - Every non-report caller/endpoint in the inventory below has explicit
authenticated success coverage, not merely a bearer header in a mock. - Missing/invalid credentials and valid credentials used on unapproved operations
are rejected. Public discovery and human login/enrollment remain intentional
and covered. - Cross-project access is denied for IDs, slugs, references, archives, and derived
lookups. An authenticated service cannot claim arbitrary run authority. - Completed, cancelled, reaped, and reclaimed jobs cannot continue reading content
or renew authority. - A job/evaluation lasting beyond one credential lifetime still works; concurrent
evaluations do not share authority or cached content. - Worker-to-judge authentication cannot be bypassed to borrow criteria access.
- Dependency outages do not turn into anonymous access or success-shaped
fallbacks. Credential rotation behavior is covered for the selected mechanism. - The auth architecture, caller inventory, environment configuration, and
AKS/Compose setup describe the delivered behavior and remaining report gap.
Non-report endpoint inventory
This inventory is a starting point, not proof that authentication or authorization
already exists. Audit actual call sites for additional non-report paths.
Worker and judge content routes on the Scope API
GET /api/v1/mcp/servers/:idGET /api/v1/skill-revisions/by-ref/:ref(*)GET /api/v1/skill-revisions/by-ref/:ref(*)/archiveGET /api/v1/extensions/:idGET /api/v1/resources/:idGET /api/v1/resources/:id/revisions/latestGET /api/v1/resources/:id/revisions/:revisionNumberGET /api/v1/resources/revisions/:idGET /api/v1/task-prompts/:idGET /api/v1/task-prompts/:id/contentGET /api/v1/codebase-revisions/:idGET /api/v1/codebase-revisions/:id/archiveGET /api/v1/criteriaGET /api/v1/criteria/:id
Include gate prompt resolution, archive downloads, and criteria ancestors.
Decide and enforce corresponding HEAD behavior rather than relying on an
implicit Express fallback.
Registration, scanning, and evaluation
- Scope API:
POST /api/v1/agents - Scope API:
POST /api/v1/agents/:id/versions - Scope API:
GET /api/v1/agents - Scope API:
POST /api/v1/models/sync - Judge service:
POST /api/v1/evaluate
Prior work and references
- Parent: Deliver authentication and RBAC across Scope #17. Human RBAC: Enforce project membership RBAC and administration #1300. Human CLI authentication: Add CLI sign-in and JWT credential management #1562.
- feat: add project membership RBAC and administration #1532 is the RBAC integration this issue is intended to unblock.
- feat: authenticate service-to-API calls (run token + service keys) #1558 is closed. Treat it as prior implementation work to inspect for reuse,
not merged functionality or an established integration target. - Issue artifact 1, Managed workload identity alternatives for service-to-API
authentication, compares platform identity options. It is research, not a
selected design or evidence of deployed configuration. docs/architecture/auth-rbac.mddescribes the human boundary and deferred
service-auth design. Amend it explicitly for the agreed initial run/project
authority model without submitter binding.- JWT-based authentication is selected; the earlier opaque-token recommendation
is superseded. Infrastructure choices are external inputs; application claim
binding, delegation, lifecycle, and RBAC integration remain explicit decisions.
Activity
duffney commentedon Oct 23, 2026
[-]Authenticate service-to-API calls so RBAC can run with auth on (unblocks #1532)[/-][+]Authenticate internal services with JWT[/+]