Skip to content

Releases: Pageloom/weft-id

v1.8.0

23 May 17:30
Immutable release. Only release title and notes can be modified.

Choose a tag to compare

Fixed

  • Outbound SCIM group membership no longer silently drops members at spec-compliant receivers. WeftID was using its own UUID as the SCIM id in Group.members[].value and in PUT/PATCH/DELETE paths. Receivers that mint their own server-assigned id per RFC 7644 §3.3 (Authentik, most spec-compliant SCIM 2.0 sources) resolve group members against that server id, so the WeftID-UUID references never matched and members landed in zero groups downstream. The worker now captures the receiver's id from the first POST response, stores it in a new mapping table, and uses it for every subsequent PUT/PATCH/DELETE and for group member references. Affects any tenant whose downstream SCIM receiver does not happen to conflate id with externalId
  • 404 on DELETE /Users/<id> or DELETE /Groups/<id> no longer dead-letters. Removing a group grant for users the receiver never saw used to flood the sync log with false failures. The Generic adapter now treats 404 on DELETE as success-like ("resource is already gone"), drains the queue row, and surfaces the outcome as an amber Skipped badge in the Sync activity panel. 404 on POST/PUT/PATCH continues to behave as before
  • 404 on PUT against a stale id self-heals. If a downstream resource is recreated (or our recorded id otherwise drifts), the next push gets a 404, WeftID clears the stale mapping, and the attempt after that POSTs cleanly to remint the mapping. No operator intervention required

Changed

  • The Atlassian quirk's "404 is permanent (already gone)" override was removed in favor of the new general policy (404 on DELETE = success, 404 on other verbs = permanent). Behavior is unchanged for the common deprovisioning case
  • GitHub Enterprise Cloud's SCIM quirk opts out of PUT-on-Groups (GitHub returns 405) via a new per-vendor GROUP_UPDATE_VERB capability flag. Behavior for GitHub tenants is preserved: groups still go through POST only, with the same 409-on-duplicate semantics as before

Added

  • New sp_scim_remote_ids table (tenant-scoped with RLS) records WeftID-id → receiver-id mappings. Migration 0041_scim_remote_ids.sql is purely additive and applied automatically on self-hosted upgrades. Rows that pre-date the table self-heal on the next push via a fallback path; no resync action is required
  • New audit events scim_remote_id_mapped (first time a receiver mints an id for a resource) and scim_remote_id_invalidated (a 404 cleared a stale mapping). Both are operational tier, visible in the audit log when operational events are shown
  • The SCIM admin guide gained a "Resource ID mapping" section explaining when mappings are created, used, and cleared, plus updated status meanings (the new amber Skipped badge) and worker reason codes (already_absent, remote_id_invalidated)
  • New dev/scim-testbed.sh bootstrap script (and make scim-testbed-{up,down,destroy,status,logs,info} targets) spins up a local Authentik instance for end-to-end outbound-SCIM testing. The Authentik runtime lives outside the WeftID checkout by default (~/.local/share/weft-id/scim-testbed/authentik/) so generated secrets and volumes can't leak into source. See dev/scim-testbed.md. Authentik is a separate MIT-licensed project; WeftID does not bundle or redistribute it
  • Dev-only: host.docker.internal is allowed as a SCIM target URL when IS_DEV=true, so WeftID's containers can reach a SCIM receiver running on the Docker Desktop host. Production builds reject it as before

v1.7.1

23 May 13:14
Immutable release. Only release title and notes can be modified.

Choose a tag to compare

Added

  • Outbound SCIM credentials can now be imported from the downstream application in addition to being generated by WeftID. Use the new Import existing token button on the SP's SCIM tab for receivers that mint the bearer token on their side (e.g. Authentik, some self-hosted SCIM servers). Generated and imported tokens are stored and pushed identically; only the source differs
  • New additive POST /api/v1/service-providers/{sp_id}/scim/credentials/import endpoint (super_admin, shares the 10/min rate-limit bucket with the existing POST /scim/credentials mint endpoint) and a distinct scim_token_imported audit event so imported credentials are auditable separately from generated ones

v1.7.0

23 May 08:35
Immutable release. Only release title and notes can be modified.

Choose a tag to compare

Added

  • Outbound SCIM 2.0 provisioning: WeftID can now push user and group changes to downstream applications, closing the gap that pure SAML cannot (a user removed from WeftID no longer retains access to downstream SaaS)
  • SCIM 2.0 push client with per-vendor quirk modules: day-one support for Slack (Enterprise Grid), GitHub Enterprise Cloud, Atlassian (Guard / Access), and GitLab.com; a spec-correct Generic SCIM 2.0 path covers everything else
  • Admin UI under each SP's SCIM tab: target URL, application type, group membership mode (effective / direct), sync activity retention (3 / 6 / 12 / 24 months / forever), and bearer-credential management
  • Bearer-credential lifecycle: tokens minted by WeftID, displayed in plaintext exactly once, Fernet-encrypted at rest; rotation with a 24-hour overlap window so in-flight pushes complete cleanly; instant revoke
  • Sync activity panel: live pending and dead-lettered counters, per-status filtering, and a "Retry dead-lettered" action that re-enqueues every dead row for the SP
  • Per-tenant background worker with retry, exponential backoff, dead-letter on retry-budget exhaustion, and per-SP sequential fan-out within a tenant slice to avoid hammering a single downstream
  • Event-log-driven dispatch: mutations tagged with a scim_trigger annotation in the event-type registry enqueue work automatically; eager fan-out at trigger time for group / membership changes so queue depth is a meaningful "work remaining" metric
  • Coalescing outbox keyed UNIQUE(sp_id, resource_type, resource_id): re-enqueues bump enqueued_at and reset attempts; the worker re-fetches current resource state at push time so "last state wins" is automatic and deprovision is just "user no longer in scope"
  • Two-log model: admin actions (token create / rotate / revoke, config edits) go to the main audit log with indefinite retention; per-push outcomes go to a dedicated scim_sync_log with per-SP retention (default 3 months, configurable to 6 / 12 / 24 months or forever for regulated tenants)
  • API endpoints under /api/v1/service-providers/{sp_id}/scim: config GET/PUT, credentials CRUD, sync-log paginated read, queue status, and retry-dead-lettered POST
  • Documentation: full admin guide at docs/admin-guide/service-providers/scim.md with per-vendor walkthroughs (Slack / GitHub / Atlassian / GitLab), credential lifecycle, sync panel reference, and a troubleshooting section
  • Inline help link from the SP detail SCIM tab to the docs page

Fixed

  • OAuth2 authorization endpoint: auth_request_id single-use replay protection now works correctly under Starlette 1.0+. The previous nested-mutation pattern silently failed to mark the session modified, so a reused auth_request_id could redirect with a fresh code instead of showing the error page

Security

  • Bumped starlette to 1.0.1 (PYSEC-2026-161 / GHSA-86qp-5c8j-p5mr: Host header URL reconstruction)
  • Bumped fastapi to 0.136.1, python-multipart to 0.0.29, psycopg-pool to 3.3.1, ua-parser to 1.0.2, and refreshed idna to 3.15 in production requirements

v1.6.0

16 May 07:38
Immutable release. Only release title and notes can be modified.

Choose a tag to compare

Added

  • Standard user attributes: a 14-attribute registry (contact, professional, location, profile categories) with per-tenant configuration for enable/required/mirror-from-IdP/locked-for-users/send-to-SPs flags
  • Tenant attribute configuration settings page (/admin/settings/user-attributes) with per-row toggles and category bulk enable/disable
  • Self-service profile attribute editing on the user profile page and admin attribute editing on the user detail tab, grouped by category
  • Admin-only "Connected IdP attributes" panel showing the per-IdP mirror snapshot for each user
  • IdP-driven attribute mirroring: SAML logins extract registry-keyed values via the per-IdP attribute mapping and mirror them into canonical user profiles
  • Downstream SAML assertion emission for enabled tenant attributes, with a per-SP "available, not sent" view and per-row SAML OID toggle in the admin attribute tab
  • Tenant-required attribute enforcement: dashboard banner for missing user-fixable fields, Admin Todo view listing every user with any missing required attribute, and a bulk force-profile-completion action that gates navigation until missing unlocked-required fields are filled
  • Opt-in scrub of mirrored attributes when disconnecting an IdP: web checkbox on the danger tab and ?scrub_mirrored_attributes=true on the DELETE API. Diverged values are preserved
  • API endpoints: GET/PUT /api/v1/tenant/attribute-config, /api/v1/users/{id}/attributes, and /api/v1/me/attributes for canonical and IdP-mirror reads/writes
  • Audit events: user_idp_attribute_mirror_failed (admin tier) and tenant_attribute_config_read_failed for visibility into mirror-write and config-read failures during SSO

Changed

  • Per-IdP attribute_mapping now accepts registry keys (jobTitle, phoneWork, etc.) alongside the existing fixed email/first_name/last_name/groups
  • New SPs are seeded with the tenant's default sendable attribute set; existing SPs are untouched
  • mirror_from_idp defaults to true on newly-enabled attributes so enabling an attribute does the obvious thing; tenants who want IdP values held only as read-only diagnostic info can turn the flag off
  • user_profile_updated event metadata now records an action per key (added/updated/cleared) instead of {old, new} values, keeping phone/mobile/address/postal-code/employee-ID values out of the event stream
  • Copy: unified "Profile attributes" naming, softer forced-mode banner, clarified flag tooltips, "Send to new SPs" replaces "Send to SPs by default", and a new docs page for user attributes
  • Documentation: scrub-on-disconnect section in the SAML setup guide, expanded audit event-type table, and seven admin/user guide pages updated for the new feature

Fixed

  • Removed the misleading "Enable all in " checkbox on the tenant attribute settings page (it overwrote partial selections)
  • Profile attribute save errors and successes now render as flash banners instead of silently appearing in the URL
  • Passkey E2E tests no longer race the auto-ceremony redirect on slow runs and leave the shared test tenant with a lingering passkey
  • Several pre-release correctness fixes on the user attributes feature (self-edit 403 on non-string user IDs, duplicate displayName SAML attribute when SPs had no mapping, stale event-log diffs, RLS-safe set-based mirror scrub)

Security

  • Bumped cryptography 46.0.7 → 48.0.0 and uvicorn 0.42.0 → 0.47.0
  • Bumped python-multipart, pyopenssl, certifi, urllib3, and pip to clear the dependency CVE backlog
  • Removed raw PII (phone, mobile, address, postal code, employee ID) from user_profile_updated audit event metadata. The audit signal (who changed which key, when, how) is preserved
  • IdP attribute mirror-write failures and tenant attribute config read failures during SSO are now surfaced as admin-tier audit events instead of only container logs

v1.5.0

25 Apr 11:07
Immutable release. Only release title and notes can be modified.

Choose a tag to compare

Added

  • Passkey authentication (FIDO2/WebAuthn): register, list, rename, and delete passkeys from the two-step verification page
  • Passkey login with a scoped ceremony and clone detection on used authenticators
  • Admin passkey management: per-user passkey view/revoke and auth-method filter on the user list
  • Tenant authentication strength policy with forced TOTP enrollment and platform-MFA requirement
  • Passkey enrollment accepted under the enhanced auth policy
  • API endpoints for SAML IdP reimport-xml and SAML debug entry retrieval (with response schemas)
  • API endpoint to clear all group relationships in one call
  • Admin passkey API endpoints (list, revoke)

Changed

  • Renamed "two-step verification" copy where it was inaccurate now that passkeys are available
  • Passkey-related copy aligned across templates and emails (revoke terminology, MFA reset docs)
  • Tenant auth strength selector switched from a dropdown to radio buttons
  • Passkey clone detection raises a typed exception instead of matching error strings

Fixed

  • Enforce require_platform_mfa on SAML IdP login (policy was not applied on that path)
  • Enhanced auth policy bypass via email OTP closed
  • TOCTOU race in passkey complete_authentication
  • Passkey-existence oracle on the login page (revealed whether a user had a passkey registered)
  • Migration 0032 conflict with baseline schema on fresh installs

Security

  • WebAuthn RP ID now derived from the tenant record, not request headers (prevents RP ID spoofing via Host/Origin manipulation)
  • Require user verification (UV) in all WebAuthn ceremonies (registration, authentication, reauth)
  • Bounded request body size and tightened WebAuthn input schemas
  • Rate limits on passkey registration and enrollment endpoints
  • Plain admins can no longer revoke super_admin passkeys (privilege escalation blocked)
  • Updated lxml and python-multipart to fix CVEs
  • Minor dependency bumps: click, werkzeug, python-dotenv, ua-parser-builtins, watchfiles

v1.4.1

13 Apr 20:36
Immutable release. Only release title and notes can be modified.

Choose a tag to compare

Security

  • Updated Pillow to 12.2.0 to fix GZIP decompression bomb vulnerability
  • Updated pytest to 9.0.3 to fix insecure tmpdir handling

v1.4.0

13 Apr 20:25
Immutable release. Only release title and notes can be modified.

Choose a tag to compare

Added

  • SAML assertion debug log for troubleshooting authentication failures, accessible at Audit > SAML Debug with optional verbose logging for successful assertions
  • SAML assertion replay prevention via Memcached (each assertion ID is cached and rejected on resubmission within its validity window)
  • SAML assertion attribute resilience: missing optional attributes (first name, last name) no longer block sign-in. Existing user values are preserved.
  • Automatic user attribute sync from the upstream IdP on each SAML sign-in (first name, last name updated when they differ)
  • Failed SAML authentication attempts are now always logged with full diagnostic details
  • SLO URL editing for metadata-imported service providers (previously read-only)

Changed

  • IdP-assigned users skip the password-setting step during onboarding and are directed to sign in through their identity provider
  • SAML Debug Log moved from Settings to the Audit section in navigation
  • Profile editing policy (allow_users_edit_profile) now enforced in the service layer, covering both web UI and API

Security

  • Added max_length constraints to all Form() parameters to prevent oversized input attacks (e.g., CPU exhaustion via Argon2 with megabyte-length passwords)
  • Fixed XSS in assertion attribute preview where user-controlled data was interpolated via innerHTML without escaping
  • Blocked SSRF via redirect following in SAML metadata URL fetch
  • Fixed open redirect via unvalidated SAML RelayState parameter
  • Replaced sequential integer nonces with cryptographically random tokens for email verification and password-reset links
  • Removed unauthenticated check-email API endpoint (user enumeration vector)
  • Removed super admin self-reactivation bypass; all reactivations now require admin approval
  • Restricted B2B OAuth2 client management to super admins (was admin+)
  • Rate-limited the account reactivation endpoint
  • Certificate rotation grace period bounded to 0-90 days
  • PII redacted from verbose SAML assertion event log metadata
  • Docker containers now run as a non-root user
  • Install script generates a random database password for the application user
  • Install script sets .env file permissions to 600 (owner-only read/write)
  • On-demand TLS certificate issuance restricted to registered tenant subdomains

v1.3.0

10 Apr 14:57
Immutable release. Only release title and notes can be modified.

Choose a tag to compare

Added

  • Per-SP AES-256-GCM assertion encryption (opt-in) for SAML IdP connections, replacing CBC where enabled
  • Auto-download of the Tailwind CSS binary on first use (no manual install required)

Changed

  • Renamed remaining "Loom Identity Platform" references to "WeftID" in X.509 signing certificates and the API schema title
  • Role values now display as "Super Admin" / "Admin" / "User" instead of raw database values across all templates
  • Consolidated repo root: moved compose files, shell scripts, and project management files into dedicated directories; retired shell scripts in favor of make targets

Security

  • Fixed CBC padding oracle vulnerability on SAML ACS endpoints
  • Scoped the SAML ACS rate limit key per tenant to prevent cross-tenant denial-of-service via shared egress IPs
  • Updated cryptography from 46.0.6 to 46.0.7

v1.2.0

05 Apr 18:58
Immutable release. Only release title and notes can be modified.

Choose a tag to compare

Added

  • Streamlined sign-in flow that routes directly to auth method without email verification, with tenant opt-in setting to preserve the old discovery flow
  • Bulk user operations from the user list: inactivate/reactivate, add to group, add secondary emails, and change primary email with dry-run SP assertion impact preview
  • User audit export as password-encrypted XLSX (Users, Group Memberships, App Access sheets)
  • Audit log XLSX export with optional date range, replacing the JSON export
  • Audit event visibility tiers (security, admin, operational, system) with color-coded UI toggles and API filter support
  • Resend invitation email for pending users with nonce-based link invalidation
  • Branded email headers with tenant logo and name across all 15 outbound emails, plus a Pageloom footer
  • User list filter panel redesigned as floating popover with IS/IS NOT toggle, filter negation, group hierarchy inclusion, and tinted active-state borders
  • Contextual documentation links on admin pages (information-circle icon linking to relevant docs)
  • Icons on action bar buttons

Changed

  • Email management is now admin-only; self-service email add/remove/promote/verify removed from user accounts
  • Sign-in flow defaults to skipping email verification (old behavior available via require_email_verification_for_login tenant setting)
  • Consolidated tenant name and site title into a single field (tenants.name)
  • Standardized product name to "WeftID" across all user-facing copy
  • Renamed "MFA" to "two-step verification" in emails and exports
  • Authorization denial logs moved from tenant audit trail to application logs
  • Removed weftid management script in favor of documented Docker Compose commands

Fixed

  • Fixed XSS in bulk email template where user-controlled names were interpolated via innerHTML
  • Fixed group picker missing group_type data and modal backdrop issues
  • Fixed export file passwords persisting in the database after file expiry (now redacted)
  • Fixed flaky test_claim_next_task in parallel test runs

Security

  • Set-password and invitation links are now one-time use via nonce-based invalidation (migration 0023)
  • Bounded bulk operation list fields to max 5000 items to prevent resource exhaustion
  • Export file passwords are redacted from the database after the download window expires

v1.1.0

21 Mar 18:05
Immutable release. Only release title and notes can be modified.

Choose a tag to compare

Added

  • Group assertion scope setting to control which groups are shared in SAML assertions (access-relevant, trunk, or all) with per-SP override and consent screen disclosure
  • Email deliverability verification CLI (python -m app.cli.verify_email) for checking SPF, DKIM, and DMARC before tenant provisioning
  • Self-hosting upgrade and backup documentation with full rollback procedure

Changed

  • Restructured self-hosting guide as a numbered first-setup flow with install directory guidance
  • Self-hosting docs now emphasize that SECRET_KEY and POSTGRES_PASSWORD are irrecoverable
  • Standardized password error messages across all password templates
  • Rebuilt documentation site with Zensical 0.0.28

Fixed

  • Fixed production Docker image showing "dev" as the version when the build arg was not explicitly passed
  • Fixed incorrect role list in self-hosting backup documentation (removed unused migrator role)

Security

  • Fixed LIKE wildcard injection in search queries where %, _, and \ in search terms were interpreted as SQL wildcards instead of matching literally
  • Added rate limiting to password change endpoints (5 per user per hour, 10 per IP per hour)
  • Fixed content injection via unvalidated query parameters in password-related templates