Skip to content

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, this project adheres to Semantic Versioning, commits follow Conventional Commits, and this changelog is generated by Structured Changelog.

Unreleased

v0.17.0 - 2026-10-18

Highlights

  • Relying-party applications manage managed principals through SystemAuth: a /managed-principals API served by systemauthsvc, called with the manager's access token, and the mpclient Go client
  • Nobody becomes a manager without agreeing: managers other than the creator join by invitation or claim
  • The contract's identity, policy and audit operations refuse requests until the application is federated

Upgrade Guide

  • Standalone applications that serve the contract API: set Config.AllowUnauthenticatedStandalone in development and tests, or federate the application; identity, policy and audit operations otherwise answer 403
  • Code calling managedprincipal.Service.Create with managers other than the actor, or AddManager: invite those managers or issue a claim, or build the service with WithDirectManagerAdds for administrator tooling
  • Managers in roles registered with WithRoles can no longer issue login tokens; issue them as a guardian or educator
  • To let a relying party manage managed principals, enable managed_principals for the deployment and its client and add systemforge:managed_principals to the client's scopes

Added

  • SystemAuth built by systemauthsvc serves the managed-principal API at /managed-principals when managed principals are enabled, for relying parties calling with a manager's access token granted systemforge:managed_principals; Options.AuditEmitter, ManagedPrincipalRates and ManagedPrincipalOptions, and Service.ManagedPrincipals() (a76d041)
  • managedprincipal.NewHandler relying-party mode (WithRequestClient): the client is the access token's, creation names only the caller, unknown and unmanaged principals answer 403; WithCodeRateLimit for code routes; GET / (Service.ListManagedBy) and POST /{id}/login-tokens (af30b5b)
  • managedprincipal/mpclient, a typed client for the managed-principal API with errors wrapped in *APIError (eaca813)
  • systemauth.Server.BearerAccess and BearerAuthenticator: bearer access that carries the token's client, scopes and grant, adapted to requestprincipal (c0c4e8d)

Changed

  • BREAKING: The contract's identity, policy and audit operations answer 403 until the application is federated; Config.AllowUnauthenticatedStandalone restores the open behavior for development and tests (9883be5)
  • BREAKING: managedprincipal.Service.Create accepts only the actor as manager and AddManager is refused with ErrConsentRequired, so managers join by invitation or claim; WithDirectManagerAdds keeps direct adds for administrator tooling (53a2655)
  • Issuing a login token requires manage_credentials (bf1c347)
  • The managed-principal handler answers 403 for an unknown or unmanaged principal, as for one the caller does not manage (0124078)

Documentation

  • Managed principals guide covers the API on SystemAuth, its configuration and scope, and the client
  • INIT-SYSTEMFORGE-012 specification for managed principals in relying-party applications (a18e9f1)
  • v0.17.0 release notes; relying-party, embedding and README updates for the managed-principal API

Tests

  • The connections test checks the error RunJobs returns when its context ends (078231b)

v0.16.0 - 2026-10-14

Highlights

  • Connections can be reconnected in place, track what depends on them with bindings, and be shared with a principal through per-connection role grants
  • The connection library is renamed from connectionforge to connectforge; imports, tables (connectforge_*) and the key purpose (connectforge.credential) change, which is breaking for deployments that enabled connections in v0.15.0

Upgrade Guide

  • Update imports from connectionforge to connectforge
  • Deployments that enabled connections in v0.15.0 must re-create connections or rename the tables and re-seal credentials; migrate does not copy rows or re-seal
  • Run systemauth migrate to create the connectforge_* tables

Added

  • POST .../connections/{id}/reconnect, GET, PUT and DELETE .../connections/{id}/bindings, and GET, PUT and DELETE .../connections/{id}/grants/{principal} (5a4bf33)
  • systemauthsvc registers the systemforge_connection resource type so connection grants are role grants read by the role-based provider (8f501c3)

Changed

  • BREAKING: Depend on connectforge instead of connectionforge; tables are now connectforge_* and credentials are sealed under the connectforge.credential purpose (7eb410b)

Dependencies

  • 1 dependency update

Documentation

  • Connections guide covers reconnecting, bindings and grants; ADR-017 updated for the rename and the grant vocabulary (0a5c80b)

Tests

  • Cover reconnect, bindings and grants over the API (26d6b64)

v0.15.0 - 2026-10-13

Highlights

  • Key management: keys wires keyforge as the platform's one key library, with envelope encryption, rotation without re-encrypting, the root key read through omnivault, and key events sent to the audit trail (ADR-013)
  • Connections to external services: connections composes connectionforge so organizations connect accounts at services such as a CDN or analytics product, with credentials sealed under managed keys and applications receiving an authenticated HTTP client, never the secret (ADR-017)
  • A connections API at /api/v1/organizations/{org}/connections, enabled by the new connections configuration section and protected by systemforge:connections:read and :write scopes
  • Invite-only sign-up: a gate on social login that admits only verified emails holding an invite, a consent-recording waitlist for everyone else, and systemauth invite and systemauth waitlist commands
  • App catalog: a host publishes the applications it runs, and the browser session lists it so each shell can show the products a person holds a role in, for a product switcher
  • Embedded SystemAuth emits the orgs claim with per-application roles, limited to the deployment's default entitlements
  • Fixed rls.Helper.SetTenant and SetUser, which failed on every PostgreSQL connection because SET LOCAL does not accept bind parameters
  • No breaking changes; run systemauth migrate for the new tables

Upgrade Guide

  • Run systemauth migrate (or systemauthsvc.Service.Migrate) to create sf_signup_invites and sf_signup_waitlist. Existing tables are unchanged and no SQL migration file is needed
  • To enable connections, add the connections section, create the root key (openssl rand -base64 32) and store it in the vault, and back up keys_dir with the database. systemauth migrate then creates the connectionforge_* tables and enables row-level security on PostgreSQL

Added

  • keys package: Open, Seal and Open over keyforge's single-host setup, with VaultSource reading the root key from an omnivault vault, and an audit sink that records lifecycle events without key material (1f3095e)
  • connections package: connectionforge's SQL store on the platform database with row-level security keyed on owner_id, credentials sealed by keys, deployment secrets read from omnivault, authorization through authz, and audit events to the platform trail (5975b1e)
  • connections.RolePermissions grants organization owners and admins view, use and manage on connections, and members view (dfcd4ed)
  • connections.Handler: the organization-scoped connections HTTP API (providers, list, connect, get, rename, test, disconnect) that never returns a credential and reports a refused view as not found (dfcd4ed)
  • connections.MigrateSchema creates the connection tables and enables row-level security without opening the keys, so systemauth migrate needs no root key (dfcd4ed)
  • systemauth.Server.BearerPrincipal and WriteBearerError authenticate API requests by bearer access token and scope with RFC 6750 responses (ccc1d03)
  • connections section of the SystemAuth configuration (keys_dir, vault, root_key, allow_private_egress), the systemauthsvc.Options.Providers registry, Service.Connections and Service.RunJobs (7b51e06)
  • systemauth serve runs the key lifecycle jobs while serving (dfb3597)
  • systemauth invite add|list|revoke and the --invite-only and --signup-denied-url flags, with SignupInvite (sf_signup_invites), the signupgate store and gate, and systemauth.SignupGate on social login (3471a81)
  • For host binaries: systemauthsvc.Options.InviteOnly, SignupDeniedURL and WaitlistPage, Service.SignupInvites and Service.SignupWaitlist, and the signupgate/signupcmd package with the invite and waitlist command groups to mount in a host's own CLI (dc2af08)
  • Sign-up waitlist: /signup/waitlist records an address with the consent text shown and its version, with SignupWaitlistEntry (sf_signup_waitlist), signupgate.Waitlist and systemauth waitlist list [--csv] and remove (72ac85b)
  • appcatalog package: App and an ordered, validated Catalog, with Static and Remote sources, the last cached and kept through an outage (538133c)
  • systemauth.WithAppCatalog serves the catalog at /.well-known/sf-apps; relyingparty.BFFConfig.Apps adds the catalog to /bff/session as apps, which a shell filters by the membership's applications; systemauthsvc.Options.Apps publishes a host's catalog and warns about entries with no registered vocabulary (31cc7a9)
  • systemauthsvc.Options.Vocabularies and DefaultEntitlements install an Ent-backed orgs claim source with application roles from approle (cffe439)

Fixed

  • rls.Helper.SetTenant and SetUser use set_config(name, value, true), which has the transaction scope of SET LOCAL and takes the value as a parameter; the previous SET LOCAL ... = $1 was a PostgreSQL syntax error (6149cc1)

Dependencies

  • 2 dependency updates

Documentation

  • Guides for connections to external services and for key management, and sections for them in the deployment guide and README (ee8b6d7)
  • Deployment guide sections for invite-only sign-up with the waitlist, and for the app catalog (2190863)
  • ADR-017 on external connections, ADR-016 on no static API keys and ADR-015 on identifier policy, slug namespaces and portability (cac014f)
  • ADR-013 makes keyforge the platform's key library, with the key subsystem, rotation policy, hybrid encryption, FIPS 140-3 and post-quantum positions, rotation and recovery drills, and the crypto specification; ADR-011 and ADR-012 add purge, provisional accounts, dormancy and offload (5460d4f)

Tests

  • rls is checked against a real PostgreSQL server, and the connections store is checked as an ordinary database role, which row-level security applies to (77b8d12)
  • The connections API is exercised end to end against a fake provider, including that no response carries a token (b9bb2db)

v0.14.0 - 2026-10-11

Highlights

  • Managed principals: humans without an email, such as young learners, created and controlled by guardian and educator managers, who sign them in with QR-friendly login tokens; opt-in per deployment and per client (ADR-005)
  • Principal is the sole identity root: the legacy User model and its dependent tables are removed, so password login, social login, federation sync, and SCIM all resolve a person to the same principal (ADR-004)
  • Resource servers can authenticate AI agents with AAuth through a protocol-neutral request principal and authenticator chain shared with bearer, API-key, and BFF-session credentials
  • Fixed a panic on every ascending SCIM list sort, including the default order
  • Security: the marketplace, organization, and invite APIs act for the authenticated caller and check organization permissions, instead of trusting IDs in the request; invite tokens are stored hashed
  • The simple and SpiceDB authorization providers grant the same organization and manager permissions, held to the base schema by a parity test and a shared conformance suite
  • Organizations without a plan: a first social login creates the person's personal organization, slugs are reserved, renamed with a cooling-off period and aliases, a personal organization converts to a team, and what an organization may use comes from its marketplace subscriptions and licenses (ADR-006)
  • Application roles per member, entitled through the marketplace, carried in the orgs claim and on invites, with relying parties reading memberships from claims by default (ADR-007)
  • Real-time invalidation of access: access tokens default to 10 minutes and are capped at 15, every access-reducing change is recorded, and relying parties refuse tokens issued before it, with polling, replay and back-channel delivery (ADR-010)
  • Resource-scoped collaborators: the collaborator organization role, resource grants with a standard viewer, contributor and maintainer ladder in both authorization modes, and invites that target one resource (ADR-008)
  • The authorization mode is configuration: the authz key selects rbac or rebac, and authz/mode.New builds the provider, syncer and grant store (ADR-008)
  • Management is derived from manager relationships; a manager can release a principal, a self-managed human can be invited to be managed or decline, and managing operations are authorized and served over HTTP (ADR-009)
  • Editor and viewer are no longer organization roles, and the organization plan column is removed; run migrations 0004 to 0009 on existing PostgreSQL databases

Breaking

  • Removed Ent schemas and packages user, membership, oauthaccount, refreshtoken, apikey, serviceaccount, and serviceaccountkeypair, with the Organization memberships, api_keys, and service_accounts edges and OAuthToken.service_account_id (05d78ae)
  • systemauth.Storage user methods are replaced by CreateHuman, GetHuman, GetHumanByEmail, GetHumanByExternalIdentity, LinkExternalIdentity, UpdateHuman, and DeleteHuman on one HumanPrincipal type; systemauth.User, LoginPrincipal, ErrUserNotFound, and ErrUserExists are removed in favor of HumanPrincipal, ErrPrincipalNotFound, and ErrPrincipalExists (d054dc7)
  • OAuthApp.owner references Principal; statically configured clients are owned by a service principal at the fixed system ID instead of a synthetic user (12f2494)
  • OAuth tokens and authorization codes drop user_id and the user edge in favor of the subject column; OAuthConsent.user_id becomes principal_id (16f7f9f)
  • SCIM users are human principals and group membership uses PrincipalMembership; users provisioned before this release are not visible through SCIM (6a12bae)
  • An existing PostgreSQL development database must run migrations/0002_drop_legacy_user_tables.sql before starting this version; fresh databases need no migration (97282d7)
  • The default BFF session cookie is sf_session instead of the Core-era cf_session; browsers holding the old cookie sign in again. Applications that set CookieConfig.Name are unaffected (94868b5)
  • organization.Service ListMembers and ListMemberships exclude inactive memberships unless IncludeInactive is passed, and take variadic ListOption arguments (3f80884)
  • mixin.UserBase and mixin.MembershipBase are removed (8c95e08)
  • Human.email is optional: a human without one is a managed principal with the identifier human:. HumanPrincipal.Email, principal.Human.Email, and contract identity types treat it as optional; existing creation paths still require an email (e89af69)
  • Marketplace checkout buys as the authenticated caller for an organization the caller may buy for, and answers 501 until marketplace.WithPurchaseAuthorizer or WithAuthorizer is configured; purchaser_id is optional, deprecated, and must equal the caller (7cf758e)
  • Marketplace listing and license operations answer 501 until marketplace.WithAuthorizer is configured and require an authenticated caller; only published listings are readable anonymously; owner_id and assigned_by are optional, deprecated, and must equal the caller (bbac538)
  • Organization API endpoints require an authenticated caller and, except creating an organization and checking a slug, answer 501 until APIConfig.Authorizer is set (08bd206)
  • Invite API endpoints require an authenticated caller and organization endpoints answer 501 until APIConfig.Authorizer is set; accepting and declining require the invite to be addressed to the caller's email; inviter_principal_id, principal_id, and the email query are optional, deprecated, and must match the caller (236c0e9)
  • Invite tokens are stored hashed and invite.Invite no longer has a Token field; the token is only in InviteResult.InviteURL. Existing PostgreSQL databases run migrations/0003_hash_invite_tokens.sql when deploying (7ccc80e)
  • spicedb.BaseSchema is now authz.BaseSpiceDBSchema: members hold contribute rather than edit on an organization, and editors are recognized (8762bc6)
  • authz.RelationshipSyncer gains AddPrincipalManager and RemovePrincipalManager; credential.Service gains IssueLoginToken and VerifyLoginToken; managedprincipal.Gate implementers also provide LoginTokenPolicy (8acce83)
  • identity/token reports typed errors (ErrInvalidAccessToken, ErrInvalidRefreshToken, ErrRefreshTokenReused, ErrDPoPMismatch, ErrScopeNotGranted) (2a3c8cd)
  • marketplace.LicenseService gains GetByStripeSubscriptionID; Stripe webhook endpoints should also subscribe to checkout.session.async_payment_succeeded (fa2a57d)
  • delegation errors are typed and an agent without a delegation is denied; signup's SignupOrGetExisting requires SignupInput.EmailVerified to return an existing account, and SignupWithInvite requires the invited email (284806d)
  • systemauth.WithUserIDHeader is removed; use WithTrustedUserIDHeader with a RequestGate (TrustedProxyNetworks or TrustAllRequests), social login, or your own SessionProvider. DefaultSessionProvider authenticates nobody by default (645c151)
  • identity/oauth's authorization endpoint refuses requests until WithUserAuthenticator or WithTrustedUserIDHeader is set, and third-party clients are refused until WithConsent is set (ef7ea3d)
  • session/ratelimit: IPKey and the Limiter default no longer read X-Forwarded-For or X-Real-IP (use ForwardedIPKey or ForwardedClientIP behind proxies), the middleware answers 503 on storage errors unless WithFailOpen is given, and MemoryStorage returns ErrTooManyKeys when full (3019061)
  • session/bff: TrustProxy and TrustCloudflare do nothing without TrustedProxies or CloudflareIPRanges; session/middleware no longer reads forwarding headers for API key usage addresses unless an IPExtractor is given (a253f24)
  • scim: a provider without WithAuthorizationHook answers 403 to every request; DefaultAuthorizationHook is deprecated for AllowAllAuthorizationHook (0e3dd33)
  • systemauth: NewFederationEndpoints registers the sync and lookup routes only with WithFederationAuthenticator; introspection callers need a confidential client or the introspect scope (d57bf0f)
  • session/jwt and contract: tokens without exp are refused, and jwt refuses another issuer when Config.Issuer is set; relyingparty.BearerMiddleware requires an allowed Origin and JSON body for cookie-authenticated POST, PUT, and DELETE (7061c67)
  • credential.ValidateClientSecret returns ErrInvalidClientCredentials for every rejection; multiapp.AppAwareDB.ForSchema returns an error (30bd958)
  • identity/apikey: Get, Revoke, and Delete take the owning principal and report other keys as not found; a service with no AllowedScopes grants no scopes unless AllowAnyScope is set; RevokeInOrganization added for organization administrators (0a3cf11)
  • rls: Helper.SetTenant and SetUser return ErrNotInTransaction for sql.DB and sql.Conn; Middleware.SetRLSContext no longer touches the database and Middleware.WithTx scopes a transaction (ba68c75)
  • The organization plan column and organization.Plan constants are removed from the schema, service inputs, list filter, API and SCIM group provisioning; organization responses carry an entitlements list instead. Existing PostgreSQL databases run migrations/0004_drop_organization_plan.sql (5172a12)
  • editor and viewer are no longer organization roles: the roles are owner, admin, member and collaborator, every membership path refuses any other value, and the base schema gains the collaborator relation and list permission. migrations/0008_drop_editor_viewer_roles.sql maps stored editor to member and viewer to collaborator, including pending invites (18b3a32)
  • Every path that creates or changes a membership validates the role against owner, admin, member and collaborator and answers ErrInvalidRole otherwise (24edc0b)
  • The marketplace SpiceDB fragment no longer redefines principal and organization; it attaches to the base organization through a marketplace_org facet carrying use, billing and purchase. Compose it with MergeSchema, which places the base schema first (3774596)
  • Entitlement checks fail closed: an approle service with no entitlement source entitles no organization to any application. Configure marketplace.EntitlementSource through marketplace.ApproleOptions, or use approle.EntitleAll in development and tests (2d11968)
  • Relying parties read memberships from SystemAuth claims by default (ClaimsMemberships); LocalMemberships is no longer picked up implicitly from the principal store and is for development and tests only (5cd6dd9)
  • The default access token lifetime drops from 15 to 10 minutes, and a configured lifetime above 15 minutes is refused at load; per-client lifetimes are capped at 15 minutes (d20202b)

Upgrade Guide

  • Run the migrations against an existing PostgreSQL database, in order: 0004_drop_organization_plan, 0005_subscriptions_per_listing, 0006_invite_app_roles, 0007_oauth_app_backchannel_logout_uri, 0008_drop_editor_viewer_roles and 0009_invite_resource_target. Each is idempotent. Fresh databases need none of them. Then run systemauth migrate for the new tables sf_app_roles, sf_slug_reservations, sf_access_changes, sf_resource_grants and sf_manager_invites
  • Replace uses of the organization plan with entitlements: remove Plan from organization inputs and filters, and read entitlements from organization responses. Supply APIConfig.Entitlements with marketplace.EntitlementSource; carry a paid tier over as a subscription or license
  • Replace editor and viewer in your own role tables, vocabularies and invites with member and collaborator (or resource roles); stored memberships are mapped by migration 0008, which records an access change for each active membership it changes
  • Configure entitlements for application roles: build the approle service with marketplace.ApproleOptions(marketplace.EntitlementSource(...)), and declare applications free to everyone with marketplace.WithDefaultEntitlements. Without them no organization is entitled to anything, and marketplace.WarnIfNoEntitlements logs a startup warning
  • Relying parties that depended on LocalMemberships must pass it explicitly. The default reads the orgs claim; use ClaimsOrRemoteMemberships to fall back to /oauth/userinfo/memberships when the claim is truncated or absent
  • Pass a revocation cache to BearerMiddleware and NewBFF to refuse tokens issued before an access change; feed it with accesschange.ToSink in one process, the poller across replicas, or back-channel delivery across deployments. Review any configured access_token_lifetime against the 15 minute cap
  • Build the authorization provider from configuration with authz/mode.New(ctx, cfg.Authz, mode.Deps{...}) and pass its Syncer to the identity services. The authz key defaults to rbac. The authz/simple and authz/spicedb forwarding packages remain deprecated and will be removed in the next major release; import authz/rbac and authz/rebac/spicedb
  • When switching to rebac, write existing memberships, application roles and resource grants into the graph through the syncer before serving requests, and write the composed schema (embedded instances always receive it; remote ones only with write_schema)

Security

  • Marketplace checkout took the purchaser from the request body, so anyone could start a purchase in another principal's name for any organization (7cf758e)
  • Marketplace listing, license, and seat endpoints acted on any IDs a request named; they now check the caller's permissions on the owning organization (bbac538)
  • The organization API listed every organization and let any caller read, change, or delete organizations, change members, and transfer ownership; it now authorizes each operation (08bd206)
  • Invite management needed no permission, and anyone holding an invite link could accept it as any principal; invites are now managed with invite_member and accepted only by the addressee (236c0e9)
  • Invite tokens were stored in plain text, so a leaked table or backup could accept invites; they are stored as SHA-256 hashes (7ccc80e)
  • SpiceDB principal and organization cleanup ignored failures and missed editor and manager relations, leaving access behind while reporting success (22f7b28)
  • Refresh-token rotation was not atomic and its revocation error was discarded, so a refresh token could be used more than once; refreshing near expiry also reset a session to seven days, extending it indefinitely. Rotation is now atomic, a family keeps its first expiry, and reusing a rotated refresh token revokes the family (2a3c8cd)
  • Stripe checkout granted licenses for sessions completed with an unpaid delayed payment, a malformed seat count produced an unlimited seat-based license, and cancelled subscriptions kept their licenses (fa2a57d)
  • Deactivating a principal left its access tokens valid and let its refresh tokens keep issuing new ones for up to the family's absolute lifetime; SystemAuth and identity/token now refuse an inactive principal's tokens wherever they are used or refreshed, and revoke the family (ebe913d)
  • Revoking an agent's delegation gave it unrestricted access, constraints that did not overlap allowed everything, and delegation expiry and action limits were never stored; delegation now fails closed and enforces every constraint (284806d)
  • UpdateHuman granted or revoked platform administration without syncing it, so a revoked administrator stayed one in SpiceDB (5e002b3)
  • SignupWithInvite let anyone holding an invite link join under any email, and SignupOrGetExisting returned an existing account for an unverified email (e6d07df)
  • SystemAuth's default session provider and identity/oauth's authorization endpoint took the user from an X-User-ID request header, so anyone who could reach the endpoint could obtain an authorization code, and tokens, for any user; header identity is now an explicit, gated opt-in and the default authenticates nobody (645c151)
  • identity/oauth granted every requested scope to every client without consent; non-first-party clients now need a consent check (ef7ea3d)
  • SCIM listing and search never asked the authorization hook, so any caller with a token could dump every user and group, and the provider's default hook allowed everything; listings are authorized and the default denies (0e3dd33)
  • The federation identity sync endpoint trusted any well-formed request and acted on its body, letting an unauthenticated caller link to and then deactivate or rewrite any account by email; it and the lookup endpoint now require a FederationAuthenticator and are not registered without one (d57bf0f)
  • Rate limits keyed on client-supplied X-Forwarded-For and X-Real-IP, so a client could evade a limit by rotating the header or poison a victim's; they key on the direct peer, and forwarded headers are believed only from configured trusted proxies, here and in the BFF client IP handling and the API key middleware (3019061)
  • The in-memory rate-limit store grew without bound from attacker-chosen keys, the middleware failed open on storage errors, and the login token endpoint keyed on raw client_id values; the store is bounded, the middleware fails closed, and only registered clients get a bucket (3019061)
  • Token introspection accepted any valid access token or any client's Basic credentials, public clients included, as the caller's credential; it now requires a confidential client or a token with the introspect scope (5e6dba0)
  • The default storage accepted every client-assertion JWT ID as new, so a captured private_key_jwt assertion could be replayed until it expired (2ae4f56)
  • BFF cookies lost Secure and HttpOnly when a CookieConfig omitted them; both are now unconditional unless AllowInsecure is set for development (d1d897c)
  • Cookie-authenticated writes through relyingparty.BearerMiddleware skipped the same-origin check, allowing cross-site requests (ebf1095)
  • JWT validation accepted tokens with no expiry and ignored the issuer; the contract middleware did the same and skipped the audience check without an app ID (7061c67)
  • Client secret validation revealed whether a client ID existed by error message and timing, and lockout counted differently spelled identifiers separately, restarting the count (30bd958)
  • multiapp's SchemaDB left a schema's search_path on pooled connections, which could carry one application's schema to unrelated code, and ForSchema interpolated unvalidated names into SQL (012e2db)
  • The BFF proxy forwarded the browser's session cookie upstream when a ProxyConfig was built by hand; Cookie, Authorization, and DPoP headers are now always stripped (3c54fc2)
  • multiapp trusted the X-App-ID header, so with a shared signing key a token for one app authenticated requests for another; MiddlewareConfig.AppAudiences binds tokens to the routed app (73e0d19)
  • API keys could be read, revoked, or deleted by ID alone, requested any scope including the wildcard when no allow-list was set, and ignored MaxKeysPerUser (0a3cf11)
  • Lockout let a burst of parallel guesses exceed MaxAttempts; Lockout.Begin reserves the attempt before the credential is verified (43c3818)
  • Concurrent BFF refreshes spent one refresh token several times, which token reuse detection treats as theft; refresh is now serialized per session (a77d8df)

Added

  • identity/requestprincipal: a protocol-neutral RequestPrincipal, an Authenticator interface, and middleware that tries authenticators in order and challenges with every protocol when none recognizes the request (780ef1a)
  • relyingparty.NewRequestAuthenticator adapts bearer authentication (SystemAuth access tokens, API keys, BFF sessions) to the request authenticator chain (d86c3f0)
  • identity/requestprincipal/aauthrs authenticates AI agents at resource servers with AAuth: message-signature and token verification, an issuer allowlist checked before key discovery, per-route scopes, and AAuth-Requirement challenges (afd69bb)
  • migrations/0002 creates the system service principal, reassigns OAuth apps owned by legacy users, and drops the legacy tables and columns on existing PostgreSQL databases (97282d7)
  • A repository-wide test fails on references to the retired legacy identity model in code or current documentation (2b45328)
  • identity/clientassertion records used client-assertion JWT IDs in sf_client_assertion_jtis for replay protection (bd8af95)
  • store.Config.TrustProvisionedEmail, off by default, marks emails written through SCIM as verified so social login can link to provisioned users (ce3ea97)
  • identity/pgschema applies PostgreSQL-only schema objects; the migrate step adds a unique index on lower(email) in sf_humans (03c314a)
  • The members endpoint accepts includeInactive to list deactivated memberships (3f80884)
  • identity/managedprincipal creates managed principals with their managers in one transaction, maintains manager relationships with a last-manager guard, and audits every action (7f4fda8)
  • ManagerRelationship (sf_manager_relationships) and ManagerClaim (sf_manager_claims) Ent schemas (93a7ecf)
  • Deployment managed_principals settings and the per-client managed_principals flag, both off by default, checked through Server.ManagedPrincipalsAllowed (12373d7)
  • login_token credentials: issued by a manager, hashed, verified in constant time, single-use option, with lifetimes from the request, the client's login_token_ttl, or the deployment default (30 days) under a ceiling (400 days); single-use tokens last 20 minutes (1f1c11b)
  • POST /login-token exchanges a login token for a SystemAuth login session, with identical responses for every failure and per-address and per-client rate limits (WithLoginTokenRateLimit) (f839fd4)
  • ID token and userinfo claim managed: true for managed principals, and relying parties read it into VerifiedIdentity.Managed (f839fd4)
  • Managers list and revoke a managed principal's login tokens, login sessions, and token families, individually or all at once, through managedprincipal.Service or NewHandler (4acc46a)
  • Guardian claims: a manager issues a single-use code that makes a human with an email a guardian; AttachVerifiedEmail turns a managed principal into an ordinary human (faf4bc3)
  • Base schema relations guardian and educator on principal with manage_account, manage_credentials, view_profile, and manage_managers; authz.ManagerRolePermissions and simple.WithManagerRoleGetter (8acce83)
  • authz.OrgRolePermissions and the PermOrg* actions name the base organization permissions both providers evaluate (fdfe9eb)
  • providertest.RunOrgPermissionTests and RunManagerRelationTests hold providers to the base schema's grants (e4279a8)
  • marketplace.PurchaserChecker and stripe.WithPurchaserChecker refuse checkout to managed principals (3abd5fb)
  • marketplace.WithAuthorizer, WithPurchaseAuthorizer, OrgRolePurchaseAuthorizer, and WithCallerResolver configure how the marketplace API authorizes callers (7cf758e)
  • organization.MembershipRoleGetter backs the simple provider with active memberships; APIConfig.Authorizer and Caller configure the organization and invite APIs (08bd206)
  • requestprincipal.PrincipalUUID resolves the caller's SystemForge principal ID (57c531b)
  • spicedb.Client.DeleteRelationships deletes relationships by filter (22f7b28)
  • migrations/0003 converts stored invite tokens to hashes (7ccc80e)
  • CI runs the PostgreSQL tests against a database service and the SpiceDB provider tests with the integration tag; SF_TEST_PG_REQUIRED makes a missing database fail rather than skip (a5af409)
  • systemauth.PrincipalStatus lets storage report whether a token's principal is active; Ent and memory storage implement it (ebe913d)
  • Agents store allowed actions, allowed scopes, and a delegation expiry (404b72c)
  • systemauth.RequestGate, TrustAllRequests, and TrustedProxyNetworks; oauth.WithUserAuthenticator, WithTrustedUserIDHeader, WithLoginURL, and WithConsent (ef7ea3d)
  • jwt.ValidateAccessTokenForAudience and middleware.HTTPAuthForAudience; ratelimit.PeerIP, ForwardedClientIP, ForwardedIPKey, WithMaxKeys, WithFailOpen; systemauth.WithLoginTokenClientIP, FederationAuthenticator, SharedSecretAuthenticator, and AuthorizeIntrospectionCaller; scim.DenyAllAuthorizationHook (3019061)
  • session/jwt: TokenOptions.Audience addresses one token to its own audience (9b46bda)
  • multiapp: MiddlewareConfig.AppAudiences binds tokens to the app a request is routed to (73e0d19)
  • identity/security: Lockout.Begin and Attempt reserve a login attempt before verification (43c3818)
  • A first GitHub or Google login creates the person's personal organization and owner membership in the same transaction as the principal, and an existing principal without one gets it on its next login; the slug is the GitHub username or the email local part, with a numeric suffix on collision (ADR-006). signup.SlugForLogin, signup.CreatePersonalOrgInTx and signup.EnsurePersonalOrgInTx expose the derivation and the in-transaction creation (1d6f996)
  • Reserved slugs: organization.ReservedSlugs lists names no organization may take, WithReservedSlugs adds product names, and signup avoids them; a managed principal's slug is a manager-entered value or a generated adjective-noun-NN, never its email (signup.SlugForManaged) (6c456ab)
  • Personal organization rules: a personal organization has one member, its owner, and refuses members, invitations, SCIM membership and ownership transfer with ErrPersonalOrganization unless the role is collaborator (8988ccf)
  • Slug rename with a cooling-off period (default 7 days, WithSlugCoolingOff), reservations in sf_slug_reservations, and aliases through ResolveSlug so old links keep working (f8c679a)
  • organization.ConvertToTeam turns a personal organization into a team in one transaction and creates a new personal organization under the handle (1569de1)
  • Entitlements derived from the marketplace: organization responses carry an entitlements list built from active subscriptions, valid licenses and default entitlements, and subscriptions may be per listing (migration 0005) (c43fedf)
  • Entitled applications: a listing may name an application, and marketplace.ApproleOptions maps subscriptions, licenses and marketplace.WithDefaultEntitlements to applications with seat limits from seat-based licenses (2d11968)
  • Application roles: the AppRole schema (sf_app_roles) and the approle service to assign, change and remove a role per principal, organization and application, with endpoints under /organizations/{slug}/members/{principal_id}/app-roles (9e8d94a)
  • Application roles reach the authorization graph through the optional authz.AppRoleSyncer (b530c81)
  • The orgs claim in ID tokens, access tokens and userinfo, and a paginated GET /oauth/userinfo/memberships (6b52b99)
  • relyingparty membership sources: ClaimsMemberships, RemoteMemberships, ClaimsOrRemoteMemberships and ProvisioningMemberships (5cd6dd9)
  • Invitations carry application roles to grant on acceptance, validated against entitlements and seats (migration 0006) (1b178fd)
  • sf_access_changes and the accesschange package record every access-reducing change in the transaction that makes it and announce it to a sink (2c3082e)
  • Access changes are recorded for member removal and deactivation, organization and application role changes, ownership transfer, principal deactivation and session or token revocation (f92470f)
  • relyingparty.RevocationCache, and BearerMiddleware and the BFF refuse tokens issued before an access change, after a clock-skew margin (975b3a5)
  • Access-change poller, replay after a restart, suspect-start mode and the GET /access-changes endpoint with the access_changes:read scope (4c0d2ce)
  • Back-channel delivery of access changes as OpenID Connect Back-Channel Logout tokens to clients that register backchannel_logout_uri (migration 0007), and relyingparty.BackchannelHandler to receive them (986a1cf)
  • Access-change reasons form an open, validated registry (529a999)
  • The resource-role ladder (viewer, contributor, maintainer) and the ResourceGranter contract (d95eaca)
  • Resource grants stored in sf_resource_grants and mirrored to the graph; the role-based provider consults and manages them (8187a9a)
  • The relationship-based provider writes grants as relationships and lists resources by lookup, and vocabulary fragments validate collaborator-able definitions (68a498e)
  • Resource-targeted invites: an invite can name a resource type, id and role, and accepting it creates the collaborator membership and the grant together (migration 0009) (8b399cc)
  • The authz configuration key with rbac and rebac modes, ModeConfig and SpiceDBConfig (537714b)
  • authz/mode.New builds the configured provider, relationship syncer and grant store from a ModeConfig, with Close (dac2d76)
  • Management is derived from active manager relationships rather than from the absence of an email; a managed identity may carry an email (eea12c3)
  • Release a principal from management, invite a self-managed human to be managed, and decline a manager invitation (6471f2b)
  • A manager invitation can be declined by the invitee (f5bef03)
  • Authorized managed-principal operations, deletion with erasure and an HTTP API for managing operations (1b65fa3)

Changed

  • authz providers are named for their mode: role-based authz/rbac (formerly authz/simple) and relationship-based authz/rebac/spicedb (formerly authz/spicedb), so another engine can sit beside SpiceDB under the same mode (f1f3c0a)
  • Federation sync records the federation identity as an ExternalIdentity; creating an identity for an existing email links it so later updates and deletes resolve to the same principal (d054dc7)
  • Human email uniqueness is enforced case-insensitively on create and update in SystemAuth and SCIM, matching the case-insensitive lookups (d054dc7)
  • SCIM userName is not case-exact (RFC 7643): lookups, uniqueness, and eq and co filters ignore case (6a12bae)
  • SCIM memberships honor the active flag, and deleting a user who belongs to a group removes the memberships instead of failing (6a12bae)
  • Creating an organization through the API makes the caller its owner, and every organization with an owner gives it an owner membership (faedc5a)
  • Listing organizations returns the caller's organizations, or all of them for platform administrators (08bd206)
  • SCIM no longer lists, reads, changes, deletes, or groups managed principals (18431bb)
  • Signup requires a bare email address (a76a721)
  • Unused stale Argon2id secret checkers are removed from the identity packages (b85abc4)

Deprecated

  • authz/simple and authz/spicedb forward to authz/rbac and authz/rebac/spicedb as deprecated packages for one release; importers should move to the new paths (f1f3c0a)
  • mixin.HumanMixin, mixin.OAuthAccountMixin, and mixin.RefreshTokenMixin: applications should authenticate through SystemAuth and link local records by sf_principal_id (80dcf1b)
  • spicedb.BaseSchema: use authz.BaseSpiceDBSchema (8762bc6)
  • identity/security: Lockout.CheckAndRecord in favor of Begin (43c3818)
  • rls: EntHook.SetContextFromContext, ContextInjector, ConnWithRLS, NewConnWithRLS, and GetConnWithRLS, which cannot take effect outside a transaction (ba68c75)
  • The authz/simple and authz/spicedb forwarding packages will be removed in the next major release; use authz/rbac and authz/rebac/spicedb (dac2d76)

Fixed

  • SCIM user and group listing panicked on every ascending sort, including the default order (7f0e320)
  • The identity/oauth Fosite storage dropped any subject that was not a UUID; tokens and authorization codes now record the subject (16f7f9f)
  • CreateClient reported every constraint failure, such as a nonexistent owner, as ErrClientExists; it now does so only for a duplicate client ID (57ece18)
  • Federation sync no longer discards lookup errors, and a delete reports synced only for an identity that was never linked (d054dc7)
  • rls.SetupTestTenant and SetupTestUser inserted into tables that no longer existed; they now create organizations, human principals, and principal memberships, and report cleanup failures (40fc9b9)
  • rls.SystemForgeTables named a table that no longer existed, so MigrateSystemForge failed; it now names sf_principal_memberships (012db98)
  • identity/oauth.NewProvider panicked on construction because its storage no longer satisfied Fosite's interfaces; it now does, checked at compile time (5e36fc3)
  • identity/oauth never recorded a token family, so revoking refresh and access tokens had no effect; tokens record their request as the family and rotation retires the exchanged refresh token (5e36fc3)
  • SystemAuth failed to record client-assertion JWT IDs under foreign-key enforcement, breaking private_key_jwt client authentication and leaving assertions replayable (bb78cf8)
  • Changing a user's email through SCIM no longer keeps the previous address's verification (ce3ea97)
  • The marketplace, organization, and invite APIs panicked at registration because list filters used pointer query parameters (52be74e)
  • The simple provider denied every organization permission check, because its permission names did not match the ones it looked up (fdfe9eb)
  • SpiceDB GetRole reported editors as non-members (8762bc6)
  • A managed principal's first sign-in to a relying party failed for lack of a verified email (b6f214a)
  • In-memory stores, password login, and federation sync could match or adopt a human by an empty email (ca80678)
  • Invite emails are matched case-insensitively (236c0e9)
  • organization.Service.Create failed for an organization without a plan instead of defaulting to free (6b3f405)
  • GetMembership reports a missing membership as organization.ErrMembershipNotFound (faedc5a)
  • identity/credential reports failures to record a credential's use and corrupt stored hashes (ErrCorruptCredential) instead of discarding them, and CreatePassword no longer creates a second password when its lookup fails (43ac1ff)
  • identity/oauth's authorization code exchange always failed and its tokens lost their subject; its grant storage now delegates to SystemAuth's, enforcing PKCE and redirect URIs and detecting code replay and refresh-token reuse (f2f71da)
  • A signup that failed after creating the user left an account with no organization whose email could not sign up again (e6d07df)
  • principal type-specific updates changed shared fields before checking the type, and CreateAgent accepted a missing or inactive delegating principal (5e002b3)
  • identity/oauth.NewAPI panicked on every call because the Fosite interceptor was added after routes (ef7ea3d)
  • The federation lookup handler read its path parameter with net/http's PathValue, which chi does not populate (d57bf0f)
  • The memory rate-limit store panicked when used after Close, and discarded windows after a fixed hour whatever their period (3019061)
  • A login with no usable characters in its username gets a neutral slug (7eaa539)
  • Accepting an invite syncs the new membership to the authorization graph (47b0cd9)
  • Principals and organizations created by social login are registered with the authorization syncer (d3566cf)
  • Signup creates the principal and personal organization in one transaction (cc58377)
  • The application-role seat limit is checked under a lock so concurrent assignments cannot exceed it (8521c37)
  • A managed principal is never a valid manager (88b8c7b)
  • Authorization checks for AddManager, RemoveManager and Release run inside the row-locked transaction (66ff372)
  • Managing operations record the accurate access-change reason (d94f453)
  • The resource schema helper keeps owner and delete (3fba5d6)
  • Assigning an application role with no seat left answers 409 instead of 500 (cbb810e)

Dependencies

  • 1 dependency update

Documentation

  • ADRs live in docs/design/adrs/ with an index of statuses, under a Design section in the docs nav; ADR-006 (organization lifecycle), ADR-007 (memberships and entitlements as claims), ADR-008 (resource-scoped collaborators, with rbac/rebac guidance) and ADR-009 (management is a relationship) are added (4ee73c5)
  • ADR-004 (retire legacy User; Principal as the sole identity root) and ADR-005 (managed principals and manager relationships), with specs for INIT-SYSTEMFORGE-007 and INIT-SYSTEMFORGE-008
  • Identity, OAuth, integration, and getting-started documentation rewritten for the principal model; the schema reference is generated from the Ent schema
  • The service-accounts page states that the RFC 7523 JWT-bearer grant is not implemented; the migration guide states that only Argon2id password hashes can be imported
  • Resource servers accepting AI agents via AAuth (00b495f)
  • Managed principals guide, with the email exception, login token security, and base manager relations added to the users, account security, and authorization conventions docs (6f9cd36)
  • Architecture pages for organizations, managed principals and authorization describe the implemented behavior (287ffaf)
  • Guides for invites, application roles and entitlements, collaborators and resource grants, organization slugs, personal-to-team conversion, access-change invalidation and the authorization mode (940fd7e)
  • Feature specifications moved from docs/design to docs/specs (30d9c8f)
  • INIT-SYSTEMFORGE-011 specifications for the organizations initiative (f41140a)

Tests

  • The test person-server client uses an explicit HTTP client (e0f1773)

v0.13.0 - 2026-10-06

Highlights

  • identity/systemauthsvc: embed SystemAuth in a host binary with config loading, production checks, migrations, client bootstrap and health
  • Production safety checks enforced by systemauthsvc.New, not only by the command
  • Service.Metadata() lets in-process relying parties skip network discovery
  • Configuration overrides apply before defaults and validation; SystemAuth configuration can be loaded from bytes

Added

  • Server.OpenIDConfiguration() and Server.Ready(ctx) on the SystemAuth server (d4e1834)
  • identity/systemauthsvc exported SystemAuth service setup for host binaries (77e642b)
  • systemauth.DecodeConfig and DecodeConfigFile decode configuration without validating (af3891e)
  • systemauthsvc.LoadConfigBytes; LoadConfig validates after overrides (974b8b0)

Changed

  • cmd/systemauth builds the server through systemauthsvc; flags and defaults unchanged, production-refusal message reworded (adf9268)

Documentation

  • Verified email design: ADR-003 and INIT-SYSTEMFORGE-006 (9786049)
  • Embedding SystemAuth in a host binary (7a7e5f5)
  • LoadConfigBytes and override ordering (f52d8f2)

v0.12.0 - 2026-10-06

Highlights

  • Social login on SystemAuth: GitHub/Google login routes, principal upsert keyed by provider subject with verified-email linking, hardened __Host-sf_login session, state CSRF + PKCE, allowlisted redirects
  • Session and token lifecycle: refresh-token rotation with reuse detection and absolute expiry, logout with token revocation, consent page
  • OpenID Connect: ID tokens, optional RS256 JWT access tokens, and the /oauth/userinfo endpoint
  • identity/relyingparty: reusable OIDC relying party with sub → sf_principal_id linking, /bff/* cookie sessions, and bearer middleware for JWTs and API keys
  • Durable stores: Ent-backed SystemAuth login sessions, login state and consent grants; identity/relyingparty/pgstore encrypted PostgreSQL session stores with key rotation
  • Production-deployable systemauth binary: PostgreSQL via pgx, signing key from a secret, health checks, and a production mode that refuses unsafe configuration

Breaking

  • Removed the unused duplicate session/oauth package; use identity/oauthclient (51f85fd)
  • cmd/systemauth without --dev refuses to start without a signing key, an https issuer, and a persistent database, and rejects insecure_cookies (bd65215)
  • Refresh tokens rotate on every use; presenting a rotated refresh token returns invalid_grant and revokes the token family (2c72979)
  • OAuth codes and tokens record a subject; auth-code user_id becomes nullable; run systemauth migrate (6ed9b76)

Added

  • identity/oauthclient: provider Connector, User.EmailVerified, and a pluggable single-use StateStore (178063d)
  • ExternalIdentity entity (sf_external_identities) linking principals to upstream logins (9d2f589)
  • SystemAuth principal directory and external-login account linking (verified-email linking only) (ae8a363)
  • social_login configuration with redirect allowlist (9ae2eb5)
  • __Host-sf_login session store and hardened cookies (35b8ba3)
  • GitHub/Google login routes on SystemAuth (a1e4310)
  • Logout and consent pages (3644e1b)
  • OpenID Connect UserInfo endpoint (adbb5b7)
  • OIDC ID tokens, optional JWT access tokens, and idp_hint (d83b627)
  • identity/relyingparty OIDC client and principal linking (2f2ef88)
  • Relying-party /bff cookie-session handler and bearer middleware (c0c6f5d)
  • Signing key loaded from a secret with a key ID, and /healthz / /readyz (d496386)
  • Production-deployable systemauth binary with PostgreSQL via pgx and env/flag configuration (bd65215)
  • Ent schemas for login sessions, login state and consent grants (52b21a5)
  • Ent-backed SystemAuth login session, login state and consent stores, used by default with database storage (311ce3a)
  • identity/relyingparty/pgstore PostgreSQL session and login-state stores with AES-256-GCM encryption at rest (0369dd5)
  • pgstore.Keys, KeysFromEnv, and NewStores for shared session-key loading and rotation (64bde37)

Changed

  • Relying-party memberships come from a MembershipSource fed by SystemAuth claims; sessions track sid for future back-channel logout (f34b05d)
  • cmd/systemauth logs whether social login state is database-backed at startup (b286d70)

Fixed

  • Refresh-token rotation with reuse detection; reused refresh tokens no longer crash the server (2c72979)
  • Query-escape the return URL in DefaultSessionProvider redirects (50743ec)
  • Update configured OAuth clients that already exist in the database on startup (ca517d3)
  • Generate the relying-party seal nonce in a dedicated buffer (sealed format unchanged) (fcce545)

Dependencies

  • 1 dependency update

Documentation

  • Centralized social login design: ADR-002 and INIT-SYSTEMFORGE-005 (66a0103)
  • Social login guide (c897f21)
  • Logout, consent, and refresh-token rotation (db3ced2)
  • SystemAuth endpoints and UserInfo (d999cd7)
  • Federating applications to SystemAuth (relying-party guide) (13afdf0)
  • SystemAuth production deployment guide (6e5f979)
  • Production stores for SystemAuth and relying parties (ec75da4)
  • NewStores and environment-based key rotation (b3dda5d)

v0.11.0 - 2026-10-02

Highlights

  • coreauth -> systemauth: the identity/auth server package, binary, bootstrap user, JWKS key id, env var, and observability metric namespace all rename; the parallel CoreControl naming is retired in favor of the same name
  • cf_ table prefix -> sf_: all 26 identity tables, via the Ent schema annotations
  • API-key visible prefix cf_ -> sf_: newly issued keys read sf_live_.../sf_test_...
  • Unified cross-app principal-link field: PrincipalMixin's sf_principal_id replaces the divergent core_control_principal_id / core_auth_principal_id spelling

Breaking

  • identity/coreauth -> identity/systemauth import path; cmd/coreauth -> cmd/systemauth binary; CoreControlConfig and related types renamed to SystemAuthConfig etc. (d97bdde)
  • All cf_ tables renamed to sf_; migrations/0001_rename_cf_to_sf.sql provided for an existing dev database with data to keep (5f78037)
  • identity/apikey.DefaultPrefix and identity/credential.APIKeyPrefix move from cf_ to sf_; dev-issued cf_-prefixed keys must be reissued (385fe99)
  • PrincipalMixin's SSO-federation link field renamed to sf_principal_id; consumers on core_control_principal_id or core_auth_principal_id must rename and regenerate Ent (5734a60)

Documentation

  • README Database Tables and Migration Strategy sections updated to sf_*

v0.10.0 - 2026-09-06

Highlights

  • Module path moved from github.com/grokify/systemforge to github.com/plexusone/systemforge; the GitHub repository was transferred to the plexusone org
  • Cross-app authorization vocabulary contract (AppVocabulary) and registry so Forge platform apps share one role/permission/scope convention
  • Shared SpiceDB base schema (principal/organization/platform) with a composition helper for app-contributed fragments

Breaking

  • Module path changed to github.com/plexusone/systemforge. Update imports from github.com/grokify/systemforge/... to github.com/plexusone/systemforge/... (the API is unchanged); the old path still resolves via GitHub's repository-transfer redirect but will not receive new tags (852744b)

Added

  • authz.AppVocabulary contract and VocabularyRegistry validating app-name format, {app}:{resource}:{verb} scope naming, role-hierarchy coverage, and {app}_-prefixed SpiceDB definitions (7886093)
  • BaseSpiceDBSchema and VocabularyRegistry.ComposeSpiceDBSchema, assembling the platform base plus every registered app fragment and rejecting duplicate definitions (d61bc4f)

Fixed

  • Close a line-anchored regex bypass in SpiceDB schema-definition detection: a fragment packing two definitions onto one physical line hid the second from both the {app}_-prefix check and the duplicate-shadowing check, while the raw fragment was still concatenated verbatim into the composed schema — letting an app silently redefine a reserved or foreign definition (3f43040)
  • Exclude github.com/KimMachineGun/automemlimit v1.0.0, which removed memlimit.SetGoMemLimitWithOpts and broke the build via jzelinskie/cobrautil/v2/cobraproclimits (a64fce1)
  • Reference the shared plexusone/.github CI workflows at @main (with check-latest: true added upstream) instead of a stale pinned tag, so go.mod's required Go patch version resolves correctly (1e27a9a)

Dependencies

  • 3 dependency updates

Documentation

  • Publish the INIT-SYSTEMFORGE-001 (unified Forge authorization/IAM/shell) and INIT-SYSTEMFORGE-002 (grokify-to-plexusone migration) initiative specs (fd97642)

v0.9.0 - 2026-08-23

Highlights

  • DPoP (RFC 9449) extracted to the standalone github.com/grokify/goauth/dpop package; consumers must update their import path
  • GuardSQL authorization adapter (authzguardsql) consolidated into SystemForge
  • OpenAPI 3.1 spec with an interactive Scalar API reference in the docs site

Breaking

  • The session/dpop package has been removed; DPoP now lives at github.com/grokify/goauth/dpop. Update imports from github.com/grokify/systemforge/session/dpop to github.com/grokify/goauth/dpop (the API is unchanged). The session/bff layer that binds DPoP to sessions remains in SystemForge (1892c0d)

Added

  • authzguardsql adapter mapping GuardSQL schemas/policies to SystemForge authorization (PolicyBuilder, ResourceBuilder, DefaultResourceBuilder); depends on github.com/grokify/guardsql (cc789a7)
  • OpenAPI 3.1 specification and a Scalar interactive API reference (b271108)

Changed

  • bff reverse proxy migrated from the deprecated httputil.ReverseProxy.Director to Rewrite (Go 1.26 SA1019), propagating the session via the outbound request context (1892c0d)

Dependencies

  • 8 dependency updates

Documentation

  • Add a query policy engines guide and integrate it across the docs (434862c)
  • Integrate the interactive API docs into site navigation (293eb0b)
  • Document the authzguardsql adapter and the guardsql rename (ac300af)
  • Update README shields (9b8c673)

v0.8.0 - 2026-06-21

Highlights

  • Organization ownership transfer with transaction-safe implementation
  • OmniStorage session backend with Redis support and size limits
  • SpiceDB API compatibility fix for v1.54.0+

Added

  • Organization ownership transfer functionality with TransferOwnership method (7be89d8)
  • POST /organizations/{slug}/transfer-ownership API endpoint (7be89d8)
  • TransferOwnershipInput type for transfer configuration (7be89d8)
  • OmniStorage session store backend with memory and Redis support (3493416)
  • Session size limits and per-user session limits with auto-eviction (3493416)
  • Site isolation for multi-tenant session management (3493416)

Fixed

  • SpiceDB client API compatibility with v1.54.0+ using grpc.NewClient (4aa41ae)

Dependencies

  • 12 dependency updates

Documentation

  • Session management overview with architecture diagram (b3d0cd6)
  • BFF sessions documentation with store interface and backends (b3d0cd6)
  • Ownership transfer documentation in memberships guide (f7218a1)

v0.7.0 - 2026-05-10

Highlights

  • BREAKING: Renamed project from CoreForge to SystemForge
  • ProductGraph integration for event correlation and tracking
  • Session invalidation with memory and Redis stores
  • Account lockout protection for identity module

Added

  • ProductGraph client for event correlation and tracking (cf8aa54)
  • ProductGraph integration with observability module (df5c013)
  • Session invalidation with MemoryStore and RedisStore implementations (b4077b1)
  • Account lockout protection in identity module (500fd61)

Changed

  • BREAKING: Renamed project from CoreForge to SystemForge - update all imports from coreforge to systemforge (dc9b68f)

Fixed

  • Session IsExpired flaky test on Windows due to time resolution (e332cfa)
  • golangci-lint errcheck, gosec G115, staticcheck SA1019 issues (16cfbe1)
  • gosec G710 open redirect and G124 insecure cookie lint issues (d8de86f)

Dependencies

  • 7 dependency updates

Documentation

  • Observability overview documentation (98b3669)
  • ProductGraph task tracking documentation (9ce6db1)
  • ProductGraph integration design documents (062b663)

v0.6.0 - 2026-04-12

Highlights

  • Multi-app platform infrastructure for running multiple SaaS apps on shared backend
  • Schema-per-app PostgreSQL isolation with X-App-ID header routing
  • SystemForge identity and session integration for multiapp deployments

Security

  • Generic 404 responses for missing/invalid X-App-ID to prevent enumeration attacks (1c85471)

Added

  • Multi-app server with MultiAppMode and SingleAppMode deployment options (a6ab2aa)
  • AppBackend interface for composable app registration with lifecycle hooks (a6ab2aa)
  • Schema-per-app database isolation using PostgreSQL schemas (app_ prefix) (a6ab2aa)
  • X-App-ID header routing for multi-tenant request dispatch (a6ab2aa)
  • Redis and in-memory cache implementations with app-scoped prefixes (a6ab2aa)
  • SystemForge identity integration with JWT claims extraction and validation (fb0ed5f)
  • Session management helpers for multi-tenant deployments (fb0ed5f)
  • Ent client factory for schema-isolated database connections (fb0ed5f)
  • HTTP middleware for authentication and tenant context propagation (fb0ed5f)
  • Example app backend implementation demonstrating AppBackend interface (0895fe0)

Dependencies

  • 2 dependency updates

Documentation

  • Multiapp architecture documentation with deployment patterns (3078737)

v0.5.0 - 2026-04-05

Highlights

  • Audience-aware JWT tokens for BFF vs API client separation
  • Ent-backed stores for API keys and BFF sessions with AES-256-GCM encryption
  • Reusable Ent schema mixins for API keys and BFF sessions

Added

  • Audience-aware JWT tokens with GenerateBFFTokenPair and GenerateAPIToken methods (8978a57)
  • AES-256-GCM token encryption for BFF sessions with Encryptor type (c101b1f)
  • Ent-backed BFF session store with automatic expired session cleanup (c101b1f)
  • Ent-backed API key store with EntClientInterface for app integration (efeecfb)
  • APIKey Ent mixin with fields for key management (prefix, hash, scopes, environment) (cda9b50)
  • BFFSession Ent mixin with encrypted token fields and session metadata (cda9b50)

Dependencies

  • 5 dependency updates

Documentation

  • JWT audience separation guide for BFF vs API tokens (4144c80)
  • Ent-backed session store integration guide (4144c80)
  • API key Ent store implementation documentation (4144c80)
  • OAuth client package documentation (4144c80)
  • Design documents for JWT audience and Ent stores features (00d784d)

v0.4.0 - 2026-03-23

Highlights

  • Backend for Frontend (BFF) package with session management, rate limiting, and API proxy
  • Public profile fields for users and organizations enabling directory listings
  • Huma framework integration for OpenAPI schema generation in BFF endpoints

Added

  • BFF HTTP handler with session creation, API proxy, and CSRF protection (76b618a)
  • Token bucket rate limiter with per-endpoint overrides and standard headers (3d4962b)
  • Client IP extraction with Cloudflare and proxy header support (4b60e87)
  • Huma API integration for BFF with OpenAPI schema generation (02c57fc)
  • Public profile fields for HumanMixin (slug, headline, bio, social links) (a4a52b7)
  • Public listing fields for OrganizationBase (tagline, description, website) (156ff92)

Dependencies

  • 3 dependency updates

Documentation

  • BFF pattern documentation with architecture and integration examples (92590b0)

Infrastructure

  • Updated shared CI workflows to Go 1.26.x only (126ca83)

v0.3.0 - 2026-03-14

Highlights

  • Vendor-agnostic observability integration with OmniObserve (Datadog, New Relic, Dynatrace, OTLP)
  • SaaS marketplace infrastructure with Stripe billing and seat-based licensing
  • Redis-backed rate limiting with sliding window and token bucket algorithms
  • OAuth client management and provider abstraction for CoreAuth

Added

  • Observability package with OmniObserve integration for metrics, traces, and logs (8b08c3f)
  • Marketplace package with Stripe subscription and seat-based licensing (736cca3)
  • OAuth client management service in identity/oauthclient (2bd40be)
  • CoreAPI rate limiting package with policy-based controls (be156d1)
  • Redis-backed rate limiter with sliding window algorithm (4de27f5)
  • Marketplace Ent entities: License, Listing, Subscription, SeatAssignment (daed5ba)
  • CoreAuth provider abstraction layer for pluggable authentication (6e3698d)
  • JWT claims enhancement with audience and issuer validation (7e343ee)
  • Session middleware improvements with context utilities (0ab89cf)

Dependencies

  • 3 dependency updates

Documentation

  • Authorization PRD and TRD design documents (cc4e0cd)
  • Marketplace PRD design document (cc4e0cd)
  • CoreAPI and CoreAuth documentation (cc4e0cd)

v0.2.0 - 2026-03-08

Highlights

  • SpiceDB authorization provider for Zanzibar-style relationship-based access control (ReBAC)
  • Principal-based identity model supporting humans, agents, applications, and service principals
  • SCIM 2.0 user provisioning with SystemForge-compliant patch operations
  • Identity-authorization sync automatically maintains SpiceDB relationships on identity changes

Added

  • SpiceDB authorization provider with embedded and remote modes (1bdab84)
  • Principal identity model with type-specific extensions (Human, Agent, Application, ServicePrincipal) (beb1dba)
  • GitHub-style organization system with owner, admin, member roles (f10369c)
  • SCIM 2.0 user provisioning endpoints with filter, patch, and bulk operations (e0da6c7)
  • Coreauth authentication server with Fosite-based OAuth 2.0 (0462153)
  • Credential and token management service for principals (b7cbbd7)
  • Standardized API contract module with consistent error handling (2f78fae)
  • Coreauth CLI for server and key management operations (af33be0)
  • User schema extended with profile fields (locale, timezone, avatar) (4c300f5)
  • RelationshipSyncer interface for identity-authorization integration (0d6b81e)
  • No-op syncer for deployments without SpiceDB (0d6b81e)
  • SpiceDB integration tests with embedded server (b77e366)

Changed

  • OAuth 2.0 implementation refactored for principal-based identity (09b1146)

Removed

  • Casbin authorization provider (replaced by SpiceDB) (0c01487)

Documentation

  • SpiceDB setup guide for embedded and remote modes (1bdab84)
  • SpiceDB schema reference with permission inheritance model (1bdab84)
  • Authorization integration patterns and middleware examples (0d6b81e)
  • Updated module documentation for v0.2.0 (4d676b1)

v0.1.0 - 2026-02-28

Highlights

  • Batteries-included Go platform module for multi-tenant SaaS applications
  • Complete identity management with users, organizations, and memberships
  • Full OAuth 2.0 server implementation using Fosite with PKCE, client credentials, and JWT bearer grants
  • Session management with JWT, DPoP (RFC 9449) proof-of-possession, and BFF pattern

Added

  • User accounts with email and Argon2id password hashing (0c48782)
  • Organizations for multi-tenant applications with name, slug, plan, and settings (0c48782)
  • Memberships with flexible role-based user-organization relationships (0c48782)
  • OAuth account linking for GitHub and Google providers (0c48782)
  • API key service for machine-to-machine authentication with scopes (42ce852)
  • OAuth 2.0 server using Fosite with Authorization Code + PKCE grant (91bac6c)
  • Client Credentials grant for service-to-service authentication (91bac6c)
  • Refresh Token grant with rotation and theft detection (91bac6c)
  • JWT Bearer grant (RFC 7523) for service account authentication (91bac6c)
  • Service accounts with RSA/EC key pairs for non-human identities (91bac6c)
  • Token introspection (RFC 7662) and revocation (RFC 7009) endpoints (91bac6c)
  • JWT service supporting HS256, RS256, and ES256 algorithms (1a09a05)
  • DPoP (RFC 9449) proof-of-possession token binding implementation (1f68df0)
  • Backend for Frontend (BFF) pattern with server-side sessions (bc6b81e)
  • GitHub and Google OAuth social login handlers (70a85cc)
  • JWT Bearer and API key authentication middleware (a15ac17)
  • Role-based access control (RBAC) with organization-scoped permissions (3aed18f)
  • Casbin provider for advanced policy rules (3aed18f)
  • Simple provider for lightweight permission checking (3aed18f)
  • HTTP middleware for route protection (Chi and stdlib) (3aed18f)
  • Feature flag engine with boolean, percentage, and user list flags (d7a0bcb)
  • Organization-scoped feature flag evaluation (d7a0bcb)
  • In-memory feature flag store for development and testing (d7a0bcb)
  • PostgreSQL RLS policy generation and session variable helpers (803db13)
  • Tenant isolation for multi-tenant data separation (803db13)
  • Ent ORM integration with transaction helpers for tenant context (803db13)

Documentation

  • Comprehensive MkDocs documentation site with Material theme (a52d6d6)
  • Getting started guides: installation, quickstart, configuration (a52d6d6)
  • Identity module documentation: users, organizations, memberships, API keys (a52d6d6)
  • OAuth 2.0 documentation: apps, authorization code, client credentials, service accounts, tokens (a52d6d6)
  • Integration guides: existing apps and migration (a52d6d6)
  • API reference and Ent schema documentation (a52d6d6)
  • PRD and TRD design documents for authentication and OAuth (aad6a32)
  • README with badges, quick start examples, and module structure (ac04664)

Infrastructure

  • GitHub Actions CI workflow for build and test (e2f98d5)
  • GitHub Actions lint workflow with golangci-lint (e2f98d5)
  • Dependabot configuration for Go modules and GitHub Actions (e2f98d5)