Skip to content

Namespace the credential subject by verified issuer #222

Closed

Description

@alukach

Phase 3 — Roles and the proxy.

Today
The minted credential records who the caller is but not who vouched for them, so every issuer's subjects share one flat namespace. That subject is also part of the proxy's cache key, so a collision affects cached authorization results too.

Do
Rewrite the principal into an issuer-qualified form before it reaches the Source API, derived from the verified iss claim.

Done when
Two issuers using the same subject string resolve to different accounts and do not share a cache entry.

Watch
Derive the namespace from the verified claim, not from Role config — one Role may trust several issuers, which would collapse them back into one namespace.

Why it blocks GitHub
GitHub counts as a second issuer. This must land before GitHub is trusted, not only before user-registered issuers.

Depends on source-cooperative/source.coop#543.


Part of source-cooperative/source.coop#491.

Activity

  1. alukach commented on Sep 21, 2026

    @alukach
    ContributorAuthor

    Scope notes from reconciling this with source-cooperative/source.coop#491:

    • This is not a localized rewrite. The mint site is inside multistore-sts (lib.rs, where sub becomes source_identity), not the proxy; the proxy's only hook sees the Role id, never the token. So it is a breaking wire-format change across three repositories — multistore release → proxy version bump → Resolve accounts by (issuer, subject) source.coop#543 — and authenticateWithOidcToken treats sub as a bare Ory identity id, so an issuer-qualified subject 401s every request until the app side lands.
    • Dual-format window. Subjects are sealed into live session tokens for up to STS_MAX_SESSION_DURATION_SECS, and the Workers cache holds old-format keys for up to 300s. Both formats are live during rollout; the rollout plan should say so.
    • Ride along: the analytics schema records user_id un-namespaced by issuer too, so historical rows are already ambiguous. Qualifying it here is cheap. Audit logging of exchanges belongs here as an acceptance criterion.
  2. alukach commented on Sep 23, 2026

    @alukach
    ContributorAuthor

    Contract change from source-cooperative/source.coop#566: the API no longer resolves (issuer, subject) to an account. Instead, after verifying a platform-IdP token and reading the account from RoleArn, the proxy calls POST /api/v1/accounts/{account_id}/trusts/exchanges with { issuer, subject } (the verified iss and sub), authenticated as that account — the same way it calls the keys exchanges route. 200 {trusted: true} means mint; 403 means deny. The principal it then forwards on proxied requests is the account id, as for API keys. Ory tokens are unchanged. Cache the answer like the keys standing (60s).

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