Metadata-Version: 2.5
Name: veltro-suite-auth
Version: 3.0.0
Summary: Veltro-owned suite authentication contracts.
Project-URL: Repository, https://github.com/veltrosecurity/veltro
Author: Veltro Security
License-Expression: AGPL-3.0-or-later
License-File: LICENSE
License-File: NOTICE
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: cryptography>=43.0.0
Requires-Dist: python-jose[cryptography]>=3.5.0
Description-Content-Type: text/markdown

# veltro-suite-auth

Veltro-owned suite session and service-token contracts with signed-realm compatibility.

This package is derived from the AGPL-3.0-or-later `veltro-suite-auth` 1.3.0 implementation originally maintained in VectorFlow. See `NOTICE` for provenance.

## Native roles

`APP_ROLES` lists the roles each product accepts. From 2.5.0, VectorFlow and
CHAD also accept `approver`, which maps to the coarse `editor` suite role on
service tokens and authority envelopes, as Warden's already did. An older
decoder rejects the whole session or token when it sees a role it doesn't
know, so a product has to ship 2.5.0 or later before an admin grants anyone
the VectorFlow or CHAD approver role.

## Authority envelope v2

From 2.6.0, the actorless `settings:read` and `settings:write` scopes are valid
for the `vectorflow` audience too, not just `chad` and `warden`. Identity
uses them to write each product's AI settings (veltro#1150).

`verify_authority_envelope_v2` verifies and consumes short-lived ES256
`veltro-suite-service+jwt` envelopes. The receiver supplies the exact issuer,
exact audience, active generation, that audience's public P-256 JWK ring, required
scope, and an atomic synchronous or asynchronous replay consumer. The consumer
runs exactly once after all stateless checks and must return literal `True`.

This package deliberately provides no v2 minting/signing API, private-key type,
key generator, JWKS/network fetcher, settings/environment adapter, or consumer
runtime wiring. Existing HS256 v1 compatibility remains separate and unchanged.

Actor envelopes may also carry `actor_sub` (identity's subject for the person,
a lowercase uuid) and the pair `actor_scope_kind`/`actor_team_id` (the grant the
exchange picked: `realm` with a null team, or `team` with a team id). They're
only valid next to the actor tuple. The verifier returns all three, as `None`
when the token leaves them out, so a product can resolve the actor by subject
first and fall back to email for older tokens.

## Product grant read

`product_grants_path(subject=None)` builds the path for identity's
`GET /api/authority/grants`, and `parse_product_grant_list(body, product=...,
subject=None)` checks the response strictly: the right product, canonical
subjects, native roles, a team id exactly when the grant is team scoped, and at
most the one requested subject. Bad bodies raise `SuiteAuthError` with
`GRANTS_INVALID_RESPONSE`. The product makes the HTTP call itself with its
workload credential; this package does no network I/O.

## Browser request assertion verifier

From 2.6.1, duplicate member names are checked per JSON object, so a nested
object (a team entry's `role` beside the grant's `role`) is no longer refused.
Older verifiers refuse any assertion that carries the grant's `teams` list.

`verify_browser_request_assertion` verifies and consumes short-lived ES256
`veltro-browser-request+jwt` request assertions minted by Veltro identity. The
receiver supplies the exact issuer, exact audience, active generation, that
audience's public P-256 JWK ring, the request being authorized (`request` with
`method` and `path`), and an atomic synchronous or asynchronous replay consumer.

The verifier enforces every binding the mint records: exact `typ`, `alg=ES256`
allowlist, audience key ring and `kid`, signature, issuer/audience, active
generation, nbf/iat/expiry capped at 60s, fixed realm `default`, grant-product
consistency, and — the point of the artifact — that the signed method and
canonical path match the request being authorized, using the same shared
`normalize_request_path` contract the mint uses. An assertion minted for
`GET /chad/api/alerts` never authorizes `POST /chad/api/rules`.

One-use semantics are the receiver's: after all stateless checks, the verifier
calls the replay consumer exactly once with a frozen `{issuer, audience,
generation, jti, expires_at}` tuple. The consumer must return literal `True`
only if it has not previously seen that tuple; a replayed `jti` is rejected when
the consumer returns `False`. The consumer must persist at least
`{issuer, audience, generation, jti}` until `expires_at` to enforce one-use
semantics across the token's validity window.

This package deliberately provides no request-assertion minting/signing API,
private-key type, key generator, JWKS/network fetcher, settings/environment
adapter, or consumer runtime wiring.

## Session team pick

From 3.0.0, a session's `selectedTeamId` is kept only when it matches the chrome
manifest's team id shape, `^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$`, and is
null otherwise. Nothing is trimmed. The TS and Python decoders share the rule
and the `session-v3` vectors that pin it.
