feat(auth): OAuth2 client_credentials + OIDC token exchange for non-human identities - #63
Merged
Merged
Conversation
Implement first-class machine client support for service-to-service authentication via OAuth2 client_credentials grant: - machine_clients table: OAuth2 client identity with bcrypt-hashed secrets, scope bundles, and last-used tracking - Admin CRUD API: /api/v1/machine-clients with create, list, get, update, delete, and rotate-secret operations (admin-scoped) - Machine client token endpoint: POST /api/v1/auth/token with grant_type=client_credentials supports HTTP Basic Auth or form body client auth; issues short-TTL (15 min) access tokens with machine marker claim and constant-time secret verification - AuthService extensions: create_machine_client, verify_machine_client (timing-safe), create_machine_access_token, scope validation, last_used_at tracking - Migration: 008_machine_clients.py creates machine_client table - Tests: 19 tests covering CRUD, token grant, scope enforcement, secret rotation, and all auth flows All 170 existing tests pass; Part 1 fully green and ready for use (Part 2 OIDC token exchange committed separately). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Implement federated workload identity support (Part 2) extending the /api/v1/auth/token endpoint to support OIDC token exchange: - oidc_trust_anchors table: Trusted OIDC issuers with audience, JWKS URL or static PEM keys, allowed scopes, subject patterns - Admin CRUD API: /api/v1/oidc-trust-anchors with create, list, get, update, delete operations (admin-scoped) - Token exchange endpoint: POST /api/v1/auth/token with grant_type=urn:ietf:params:oauth:grant-type:token-exchange; validates external OIDC tokens, enforces issuer trust anchors, subject pattern matching, and scope subset constraints; issues short-TTL machine tokens - AuthService extensions: validate_oidc_token (signature + claims), subject_matches_pattern (glob support) - Migration: 009_oidc_trust_anchors.py creates oidc_trust_anchor table - Tests: 9 new tests covering CRUD, token exchange validation, pattern matching, scope enforcement, issuer lookup, and error flows Enables Kubernetes service account tokens and GitHub Actions OIDC to authenticate with zero static secrets. Both Part 1 and Part 2 ship fully green with all 170 tests passing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Sorry @PenguinzTech, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
This was referenced Jul 26, 2026
Combines both sides' additions rather than picking one: - app/__init__.py: register both machine_clients_bp/oidc_trust_anchors_bp (this branch) AND audit_bp (already-merged #61) — both blueprint sets now registered, neither dropped. - app/schema.py: both machine_client/oidc_trust_anchor tables (this branch) and audit_event table (#61) now defined side by side. - tests/test_schema.py: expected-tables set includes all five new tables from both branches. - alembic: 008_machine_clients and 008_audit_events both claimed down_revision=007_revoked_token (two branches minting migration "008" independently). Re-chained machine_clients after audit_events (008_audit_events -> 008_machine_clients -> 009_oidc_trust_anchors) so the migration graph has a single linear head instead of two. - .pre-commit-config.yaml: also fixed the hadolint v2.13.0 pin (never a real tag -> v2.13.1), the unquoted flake8 --select YAML flow sequence (commas split it into bogus positional filename args), and switched gitleaks to `protect --staged` (scans only what's committed, matching PR #77's approach — the standard pre-commit pattern, no allowlist needed) instead of a full-tree scan. v2.1.x doesn't have these fixes yet since #77/#78 haven't merged; this converges toward the same fix ahead of that. Full manager suite: 200/200 passing after the combine. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PenguinzTech
added a commit
that referenced
this pull request
Jul 27, 2026
008_add_mfa_fields (#62) and 008_machine_clients/008_audit_events (already-merged #61/#63) both independently claimed down_revision=007_revoked_token, creating two divergent heads (009_oidc_trust_anchors and 008_add_mfa_fields). Git's merge saw no textual conflict since they're different files, so this surfaced only after the merge completed. Re-chained 008_add_mfa_fields after 009_oidc_trust_anchors so the migration graph has a single linear head again. Full manager suite: 229/229 passing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First-class non-human identities. Part 1:
machine_clients(bcrypt secrets shown once, rotation endpoint, per-client tenant+scopes) + OAuth2client_credentialson POST /api/v1/auth/token — constant-time verification, scope-subset enforcement, 15-min tokens, no refresh tokens for machines. Part 2:oidc_trust_anchors+ RFC 8693-style token exchange validating external OIDC tokens (JWKS or static PEM, RS256/ES256 only, glob subject patterns) — lets K8s service accounts, GitHub Actions, and AI agents authenticate with zero static secrets.Tests: 170 green (28 new, JWKS stubbed — no network).
Merge note: contains alembic migrations
008/009— collide with 008 in the MFA and audit branches; renumber whichever merges later.Stack note: bases on
chore/dedup-reusable-code(top of the #53–#59 chain); auto-retargets towardv2.1.xas the stack merges bottom-up.🤖 Generated with Claude Code