Skip to content

chore: harden core identity provider authentication and sync#122

Merged
albanm merged 3 commits into
masterfrom
chore-improv-core-id-provider
Apr 27, 2026
Merged

chore: harden core identity provider authentication and sync#122
albanm merged 3 commits into
masterfrom
chore-improv-core-id-provider

Conversation

@albanm
Copy link
Copy Markdown
Member

@albanm albanm commented Apr 27, 2026

Fixes some gaps in core id provider promises and actual implementation.

albanm and others added 3 commits April 27, 2026 16:17
Compact reference covering the coreIdProvider concept, configuration,
data model, lifecycle (login adoption, conflict guard, patchCoreAuthUser,
keepalive refresh), the idp-flag restrictions, member role/department
auto-sync, and pointers to the cross-site / email-trust trust boundaries.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A user pre-existing as a local-password account that subsequently logs
in via a core identity provider was adopted into that provider but kept
its password (and 2FA) intact, leaving the password channel as a parallel
authentication path that the schema description on coreIdProvider
explicitly forbids. Revoking access at the IdP would refresh-fail the
SSO session but the password still worked.

Two-pronged fix:

- patchCoreAuthUser now clears password, passwordUpdate and 2FA at
  binding time (mongo patchUser translates null -> $unset).
- /auth/password and /auth/passwordless reject any target user with
  coreIdProvider set, returning the existing enumeration-resistant shape
  (badCredentials 400 / silent 204). Defense in depth against any
  residual credential data from older accounts.

Tested by an api spec that creates a password account, sanity-checks
password login, triggers OIDC core adoption on the same email, and
asserts the second password attempt is now refused.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
patchCoreAuthUser auto-applied memberships returned by the core IdP via
storage.addMember on every login. Under multiRoles=true, addMember keys
memberships by (org, dep, role) — so when a provider-asserted role
changed between two logins of the same user, a duplicate membership was
appended instead of the existing one being updated. Memberships the
provider no longer asserted at all stayed on the user record forever.

Read-only memberships are only ever set via this auto-sync path
(authProviderMemberInfo flips readOnly=true when a core IdP also
configures memberRole or memberDepartment), so dropping all readOnly
entries before re-applying the current set is safe and gives the IdP
authoritative control over the slice of the user's memberships it owns.

Surfaced by the existing oidc.api.spec.ts:50:3 test, which asserts a
single replaced membership on second login but was producing two stacked
entries until now.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@albanm albanm merged commit 85d1f13 into master Apr 27, 2026
4 checks passed
@albanm albanm deleted the chore-improv-core-id-provider branch April 27, 2026 15:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant