Skip to content

feat(oidc): let a backend client send account notices for its linked public clients - #565

Merged
Bccorb merged 1 commit into
mainfrom
feat/oidc-client-links
Nov 3, 2026
Merged

Bccorb merged 1 commit into
mainfrom
feat/oidc-client-links

Conversation

@Bccorb

@Bccorb Bccorb commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Closes #547. Implements ADR 0002, N4 and N5.

What

  • Client links. A new oidc_client_links table (composite primary key, foreign keys that cascade on delete, a reverse index on linkedClientId, no self links) and admin routes:

    • GET /admin/applications/:id/links returns { links, linkedFrom }.
    • PUT /admin/applications/:id/links/:linkedId is idempotent, needs step-up, and is audited as admin_oidc_application_link_added.
    • DELETE /admin/applications/:id/links/:linkedId needs step-up and is audited as admin_oidc_application_link_removed.

    A link is refused unless the acting application is confidential, the linked one is a different public application, and both are first-party or both third-party (third-party links also need third_party_clients_enabled). The same rules are checked again every time a link is used, so disabling a client or moving it across the first-party boundary ends the link's effect at once. Deleting an application removes its links in both directions. Every application response now lists links, linkedFrom and noticeActionOrigins.

  • Notices through a link. POST /applications/account-notices takes an optional clientId. When it is set, the caller must hold a link to that client, and the grant check (hasOidcGrantForUser) and the template ([<linked name>] ..., Sent by <linked name> through <instance>) use the linked client. A missing link, a disabled linked client or a link that breaks the rules answers the same 404 notice_unknown_user as an unknown user. The caller's client_credentials, notices:send, noticesEnabled and rate limits still apply, and the action link is checked against the caller's origins. The auth event records clientId (the caller) and sentForClientId.

  • noticeActionOrigins on oidc_clients: bare https origins, never loopback, unique, at most 20. They are set on application create or PATCH (step-up, audited). An action link may point at these or at the caller's https redirect origins.

  • ADR 0001 D14 is amended, ADR 0002's issue table is updated, docs/admin-operations.md gains a Links section, and openapi.json and adapter-manifest.json are regenerated (the three link routes are access passthroughs).

Contract

This changes the contract. It adds routes, a request field and response fields, and nothing is removed or renamed. @seamless-auth/types 0.35 does not carry the new shapes yet, so the API extends the published schemas locally in src/schemas/oidcApplications.*.ts and src/schemas/applicationNotices.requests.ts, marked TODO(seamless-auth-types#148). Response validation would strip the new fields otherwise.

Follow-ups

Checks

  • npm run typecheck, npm run lint, npm run format:check and npm run build pass.
  • npm run coverage passes: 171 files, 2798 tests. Lines are at 99.24% and branches at 95.77%.
  • New tests:
    • tests/integration/oidc/oidcClientLinks.spec.ts covers the link routes, every refusal including both directions across the first-party boundary, idempotence and audit.
    • accountNotices.spec.ts covers sending for a linked client, the same 404 for an unlinked or missing client, a disabled linked client, one moved across the first-party boundary or made confidential, and action links checked against the caller.
    • oidcApplications.spec.ts covers noticeActionOrigins validation and auditing, and link cleanup on delete.
  • The migration was run up, down and up against a scratch Postgres 18. The new tests/postgres link specs pass there: the real lookup, idempotent creation, the self-link check constraint, and cascades from both sides. One existing spec there, application resources, fails the same way on main in that local database (system config validation), so it is unrelated to this change.

…public clients

Adds oidc_client_links with admin routes under /admin/applications/:id/links,
an optional clientId on POST /applications/account-notices, and
noticeActionOrigins on applications. Amends ADR 0001 D14.

Closes #547
@Bccorb
Bccorb merged commit f82ec0c into main Nov 3, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(oidc): let a backend client send account notices for its public client

1 participant