Skip to content

Authenticate internal services with JWT #1557

Open

Description

@duffney

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_TOKEN raw-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/:id
  • GET /api/v1/skill-revisions/by-ref/:ref(*)
  • GET /api/v1/skill-revisions/by-ref/:ref(*)/archive
  • GET /api/v1/extensions/:id
  • GET /api/v1/resources/:id
  • GET /api/v1/resources/:id/revisions/latest
  • GET /api/v1/resources/:id/revisions/:revisionNumber
  • GET /api/v1/resources/revisions/:id
  • GET /api/v1/task-prompts/:id
  • GET /api/v1/task-prompts/:id/content
  • GET /api/v1/codebase-revisions/:id
  • GET /api/v1/codebase-revisions/:id/archive
  • GET /api/v1/criteria
  • GET /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

Activity

  1. duffney commented on Oct 23, 2026

    @duffney
    Author
  2. changed the title [-]Authenticate service-to-API calls so RBAC can run with auth on (unblocks #1532)[/-] [+]Authenticate internal services with JWT[/+] on Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions