feat(scim): SCIM 2.0 user provisioning with deprovision-kills-sessions - #73
Merged
Conversation
Implements RFC 7643/7644 SCIM 2.0 subset for enterprise IdP (Okta/Entra) user provisioning with: - Dedicated SCIM bearer tokens (bcrypt-hashed, constant-time validation) - POST /Users (JIT create, no password set), GET (read), PUT (replace), PATCH (partial update), DELETE (soft-delete/deprovisioning) - Filtering (userName eq only) and pagination (1-based startIndex per spec) - Deprovisioning: PATCH/DELETE active=false relies on refresh_access_token's user.active check (auth_service.py:257) to fail closed; access tokens expire naturally (~15min) - Admin endpoints: /admin/tokens (mint/revoke) gated by admin:super scope and Enterprise license tier - Static metadata: /ServiceProviderConfig, /ResourceTypes, /Schemas Schema additions: - auth_user: external_id column (unique, indexed) for SCIM provisioning - scim_tokens: dedicated table for bearer tokens (id, token_hash, tenant, active, created_at, last_used_at) Migration: 010_add_scim_provisioning creates new table and columns. Comprehensive test coverage (30 tests): - Token authentication (401/403 for invalid/revoked tokens) - CRUD lifecycle (create, read, update, delete) - Filtering and pagination per RFC 7644 - Deprovisioning confirms inactive users can't refresh - Unsupported filter/path → proper SCIM error responses - Enterprise license gate on token minting - Admin scope (admin:super) gate on token endpoints All 201 backend tests pass. 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
- app/__init__.py: combined scim_bp registration (this branch) with machine_clients_bp/oidc_trust_anchors_bp/audit_bp (already merged). - app/middleware/auth.py: combined this branch's verify_jwt/has_scope helpers with the already-merged dpop_bound_token decorator -- independent, unrelated functions. - app/schema.py + tests/test_schema.py: scim_tokens table combined with machine_client/oidc_trust_anchor/dpop_replay/audit_event (all already merged). - alembic: no chain fix needed this time -- 010_add_scim_provisioning already correctly points down_revision to 008_add_mfa_fields (its actual parent when this branch was authored off feature/mfa-totp), and that chain now correctly terminates the full linear graph as a single head. Full manager suite: 323/323 passing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PenguinzTech
added a commit
that referenced
this pull request
Jul 27, 2026
- .gitleaks.toml: both branches independently created this file (add/add conflict). Kept origin/v2.1.x's version -- accumulated and already validated across #69/#71/#73/#77's resolutions. - .pre-commit-config.yaml: same flake8/hadolint divergence resolved identically to prior merges this session (single .flake8 source of truth + flake8-bugbear; hadolint v2.14.0). - app/schema.py: auth_user gained sso_provider/sso_subject (this branch) alongside external_id (#73 SCIM, already merged) -- both independent new columns, combined. - app/services/scopes.py: sso:write/sso:admin (this branch) combined with audit:read (already merged, SystemAdmin-only). - tests/test_schema.py: expected-tables set now covers sso_providers/ sso_login_attempts alongside scim_tokens/machine_client/ oidc_trust_anchor/dpop_replay/audit_event (all already merged). - alembic: SSO's own chain (008_add_mfa_fields -> 009_add_sso_providers -> 010_add_sso_login_attempts -> 011_allow_null_password_hash) and SCIM's chain (008_add_mfa_fields -> 010_add_scim_provisioning) both forked from the same parent, authored independently off feature/mfa-totp. Re-chained 009_add_sso_providers to depend on 010_add_scim_provisioning (SCIM's already-merged migration) instead, restoring a single linear head. Full manager suite: 339/339 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.
SCIM 2.0 server subset (RFC 7643/7644) so enterprise IdPs (Okta/Entra) can provision and deprovision Squawk users.
/scim/v2ServiceProviderConfig/ResourceTypes/Schemas (honest capability advertisement), Users CRUD withfilter=userName eq, 1-based startIndex pagination, PATCH subset with properscimTypeerrors. Auth via dedicated bcrypt-hashed SCIM bearer tokens (minted once-visible by admins,admin:super+ Enterprise tier gated, constant-time validation). Deprovisioning (DELETE oractive=false) disables the user — refresh continuation dies via theuser.activegate in the refresh flow (tested: the old refresh token stops working); short-TTL access tokens expire naturally.external_idcolumn added for IdP correlation.Tests: 201 green (30 new: auth 401s, CRUD cycle, filters/pagination incl. empty results, deprovision-kills-refresh proof, SCIM error shapes, license gating).
Stack note: stacks on #62 (
feature/mfa-totp) alongside the SSO branch; auto-retargets as the stack merges. Contains alembic migration010— same parallel-numbering caveat as the batch-1 auth PRs.🤖 Generated with Claude Code