Skip to content

feat(auth): add explicit identity link and safe unlink flow #655

Description

@XiaoSeS

Problem

The unified identity core can safely return LINK_REQUIRED, but users still cannot prove control of their current platform account and independently authenticate a target provider to create a binding. The platform also has no safe unlink flow that protects the final usable login method. Email, username, display name, userId, and provider:subject must never substitute for authentication.

This is PR 5 from docs/21-unified-identity-federation-design.md and is a prerequisite for secure Account Merge and for safely enabling LDAP, DingTalk, and CAS in deployments where an external identity may collide with an existing account.

Proposed Solution

Implement a server-owned, session-bound Identity Link state machine:

  1. An authenticated platform account creates a short-lived one-time intent for either LINK or UNLINK.
  2. The intent is bound to the current account and a high-entropy session nonce; only the nonce hash is persisted.
  3. The current account completes fresh reauthentication using a usable local, Browser, or Credential method.
  4. LINK independently authenticates the target Provider. The Adapter returns only ProviderAuthenticationResult; the identity core resolves the trusted Provider handle and creates Binding V2 subjects in one short PostgreSQL transaction.
  5. UNLINK revokes the selected Binding and all active subjects only when another currently usable login method remains.
  6. Completion, cancellation, expiration, replay, and concurrent consumption all fail closed and are audited without secrets.

Use a backward-compatible expand Flyway migration for identity_link_request. Keep protocol I/O outside database transactions. Do not store or log passwords, OAuth tokens/codes, tickets, cookies, raw session IDs/nonces, or raw proof.

Required API/UX Capabilities

  • List the current account’s local/external login methods without exposing external subjects.
  • Create, inspect, cancel, and consume short-lived Link/Unlink intents.
  • Local-password fresh reauthentication with existing lockout/rate-limit semantics.
  • Browser Provider reauthentication/link mode that preserves the primary Platform Session and uses the existing OAuth state validation.
  • Credential Adapter reauthentication/link mode for future LDAP/AD support.
  • Account security UI for adding and removing login methods, including explicit password reauthentication and safe callback result states.
  • Existing login, /api/v1/auth/providers, /api/v1/auth/methods, Session, Device Flow, and API Token behavior remains compatible.

Acceptance Criteria

  • No Binding can be created from email, username, display name, userId, or an untrusted provider code.
  • Current account fresh reauthentication and target Provider authentication are separate proofs.
  • Intent is bound to actor + session nonce, has a short TTL, and is one-time.
  • Expired, cancelled, completed, replayed, session-mismatched, and concurrently consumed intents fail closed with stable reason codes.
  • Link rejects subjects already bound to another account and rejects a second active Binding for the same user/provider.
  • Link reuses Registry, Authority Lock, core-owned Assertion Factory, Binding V2 constraints, and audit context; Adapter cannot create users, roles, Principal, or Session.
  • Unlink requires fresh reauthentication and rejects removal of the final currently usable login method.
  • Unlink atomically revokes Binding and active subjects and does not permit a revoked identity to log in again.
  • PENDING, DISABLED, MERGED, and system accounts cannot Link or Unlink.
  • Logs, API responses, audit detail, OpenAPI, and frontend contain no credential or raw proof material.
  • PostgreSQL tests cover expiry, replay, concurrent consume, unique-subject conflict, rollback, and final-login protection.
  • Provider Conformance boundaries remain intact; existing OAuth/OIDC regression passes.
  • Backend, frontend, E2E, upgrade, and remote test-machine checks pass on an exact big-main image revision before any main merge.

Impact

  • Auth/security: new high-risk account-control workflow; fail-closed by default.
  • Database: backward-compatible expand identity_link_request migration; first production use of Binding/Subject revocation raises the minimum safe rollback version to Binding V2-aware releases.
  • API/OpenAPI: new authenticated account-security endpoints and generated web types.
  • UX: account security page gains linked-login management.
  • Deployment: feature remains dependent on READY Registry providers and is validated on big-main first.

References

  • docs/21-unified-identity-federation-design.md §§7.7, 10.5, 12.1–12.3, 19.1, 20/PR 5
  • docs/22-secure-account-merge-acceptance-design.md fresh-reauthentication and session-binding requirements reused by the future PR 6

Metadata

Metadata

Assignees

No one assigned

    Labels

    effort/l大改动或高风险改动,需要 maintainer 负责 / Large or risky change requiring maintainer ownership.enhancementNew feature or requestpriority/p2中优先级 / Medium priority triage bucket.risk/high涉及安全、鉴权、迁移或公共契约 / Touches security, auth, migrations, or public contracts.triage/needs-info需要补充更多信息后才能分流 / Issue needs more detail before it can be routed.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions