Skip to content

Non-interactive (headless) service-token issuance #59

Description

@BizaNator

Non-interactive (headless) service-token issuance

Summary

Lore lacks a non-interactive mechanism for backend services to issue tenant-scoped, read-only service tokens for CI/CD and machine-to-machine authentication. The only token issuance paths today are interactive browser flows or OAuth token exchanges.

Current State

What exists:

  • UrcAuthApi.StartAuthSession (lore-proto/proto/auth_api.proto) returns a login_url for interactive browser-based authentication
  • ExchangeAPIKeyForUserToken exchanges external credentials, but is URC-account-shaped, not a server-issued service grant
  • JWT layer reads an is_service_account claim (lore-credential/src/jwt.rs) but there's no lore-native way to mint such tokens

File citations (pinned to rev 6559841):

  • lore-server/src/auth/mod.rs - only has jwk, jwt, middleware modules (no service token issuance)
  • lore-transport/src/auth/ucs_auth.rs - StartAuthSession is interactive-only, returns login_url
  • lore-transport/src/auth/exchange.rs - exchanges existing tokens, doesn't issue new ones
  • lore-proto/proto/auth_api.proto - no headless/service-token issuance RPC

Requested API

Add a first-class non-interactive service-account / service-token issuance path on the lore server. Example shape (adjust to lore's conventions):

message IssueServiceTokenRequest {
  string tenant_id = 1;           // Tenant/service account identifier
  repeated string scopes = 2;     // Read-only scopes (e.g., ["read:repo", "read:blob"])
  string resource_id = 3;        // Optional resource constraint (e.g., specific repository)
  int64 ttl_seconds = 4;          // Time-to-live for issued token
}

message IssueServiceTokenRequest {
  string service_token = 1;      // The issued JWT
  int64 expires_at = 2;           // Expiration timestamp
}

And corresponding Rust API in lore-transport/src/auth/:

pub async fn issue_service_token(
    auth_url: &str,
    tenant_id: &str,
    scopes: &[String],
    resource_id: Option<&str>,
    ttl_seconds: u64,
) -> Result<ServiceToken, AuthError>

Use Case

CI/CD pipelines and background services need to authenticate with lore repositories without interactive browser flows. Today, StudioBrain works around this by minting "LSG" (Lore Service Grant) tokens in its accounts service using its own keypair, which lore then verifies via JWKS. This works but couples authentication to StudioBrain's infrastructure rather than lore's.

A native lore service token issuance API would:

  • Enable headless CI/CD authentication without custom workarounds
  • Provide tenant-scoped, time-bounded, read-only tokens with proper revocation
  • Allow multiple independent services to authenticate without sharing long-lived credentials

Impact

Once this API exists, StudioBrain can retire its accounts-minted LSG workaround (see E0.2/E2.2 in StudioBrain's ADR-0001) and use lore-native service tokens instead.

Related

  • StudioBrain ticket: SBAI-4138
  • Parent tracking: SBAI-4133 (E5.3 — File lore upstream gap tickets)
  • StudioBrain ADR: docs/adr/0001-studiobrain-lore-federation.md §3.2 (LSG workaround)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions