8000 Enable DPoP for Admin and Account Consoles by edewit · Pull Request #54676 · keycloak/keycloak · GitHub
[go: up one dir, main page]

Skip to content

Enable DPoP for Admin and Account Consoles - #54676

Open
edewit wants to merge 6 commits into
keycloak:mainfrom
edewit:feat/console-dpop
Open

edewit wants to merge 6 commits into
keycloak:mainfrom
edewit:feat/console-dpop

Conversation

@edewit
@edewit edewit commented Nov 5, 2026 •
Copy link
Copy Markdown
Contributor

Closes #42813
Closes #42814

Summary

  • Bump keycloak-js to ^26.2.5 and enable dpopConfig: { mode: "auto" } in the shared KeycloakProvider
  • Route Account Console API requests through keycloak.fetch
  • Allow @keycloak/keycloak-admin-client to use a custom fetch implementation and wire the Admin Console through keycloak.fetch
  • Sync the restored application hash after login so Admin Console deep links work with createHashRouter (keycloak-js restores the hash via replaceState, which does not notify the router)
  • Document DPoP-bound console tokens in the upgrading guide

Note on setConfig

KeycloakAdminClient.setConfig() now keeps the previous requestOptions and fetch when those properties are omitted, instead of resetting requestOptions to undefined. Neither can be cleared through setConfig once set.

@edewit
edewit requested review from a team as code owners November 5, 2026 09:29
Copilot AI balanced review requested due to automatic review settings November 5, 2026 09:29
Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The fetch hook leaves other authenticated admin UI requests using global fetch with Bearer authorization, causing 401 failures when auto mode obtains a DPoP-bound token.

1 open issue
1 file not reviewed
  • js/pnpm-lock.yaml: Generated file
What changed in this PR

Adds DPoP support to the Admin and Account Consoles through the shared Keycloak adapter, addressing #54675 while retaining Bearer fallback when the server does not advertise DPoP.

Changes:

  • Upgrade keycloak-js to ^26.2.5 and enable DPoP auto mode.
  • Route Account Console API requests through keycloak.fetch.
  • Add a configurable fetch transport to the admin client and connect it to the Admin Console.
File Description
js/​pnpm-lock.yaml Lock keycloak-js to 26.2.5.
js/​libs/​ui-shared/​src/​context/​KeycloakContext.tsx Enable DPoP auto mode during initialization.
js/​libs/​ui-shared/​package.json Upgrade the shared UI adapter dependency.
js/​libs/​keycloak-admin-client/​src/​utils/​fetchWithError.ts Accept an optional fetch implementation.
js/​libs/​keycloak-admin-client/​src/​resources/​clientsV2.ts Pass custom fetch to the experimental API transport.
js/​libs/​keycloak-admin-client/​src/​resources/​agent.ts Use configured fetch for resource requests.
js/​libs/​keycloak-admin-client/​src/​client.ts Store and expose custom fetch configuration.
js/​apps/​admin-ui/​src/​admin-client.tsx Configure the admin client to use keycloak.fetch.
js/​apps/​admin-ui/​package.json Upgrade the Admin Console adapter dependency.
js/​apps/​account-ui/​src/​api/​request.ts Send account API requests through keycloak.fetch.
js/​apps/​account-ui/​package.json Upgrade the Account Console adapter dependency.

Review effort: Balanced

Comment thread js/apps/admin-ui/src/admin-client.tsx Resolved
@edewit
edewit force-pushed the feat/console-dpop branch from 7f1d8e6 to 91a9f15 Compare November 5, 2026 09:41
Copilot AI balanced review requested due to automatic review settings November 5, 2026 09:47
Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Capturing the default fetch breaks existing auth-endpoint tests by bypassing their mocks, and custom transport injection lacks regression coverage for v1/v2 calls, request options, and default-fetch fallback.

3 open issues
1 file not reviewed
  • js/pnpm-lock.yaml: Generated file

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings November 5, 2026 10:01
Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

DPoP affects authentication in both consoles, but keycloak-js auto-mode and fetch internals are outside this snapshot, leaving HTTPS proof handling and insecure-HTTP fallback dependent on browser/server integration validation.

No open issues 🎉

3 resolved since last review
1 file not reviewed
  • js/pnpm-lock.yaml: Generated file

Review effort: Balanced

@edewit edewit added area/admin/ui Admin Console — React UI for server administration area/account/ui Account Console — React UI for profile, sessions, security settings area/admin/client-js JavaScript/TypeScript admin client (@keycloak/keycloak-admin-client) area/oidc OpenID Connect / OAuth 2.0 — tokens, endpoints, scopes, DCR, PAR, DPoP area/adapter/javascript JavaScript adapter (keycloak-js) — OIDC client, token management labels Nov 5, 2026
@edewit
edewit commented Nov 5, 2026
Copy link
Copy Markdown
Contributor Author

@ssilvert @mposolda could you take a look when you have a chance?

Review focus

  • Enable dpopConfig: { mode: "auto" } in shared KeycloakProvider (with keycloak-js ^26.2.5)
  • Wire Admin + Account Consoles through keycloak.fetch so DPoP proofs are attached
  • Admin client: injectable fetch for v1/v2 + remaining Admin UI fetchWithError call sites

Closes #42813 and #42814. Copilot comments are addressed; CI was still running last I checked.

Copilot AI balanced review requested due to automatic review settings November 6, 2026 11:01
Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The fetch wrapper drops existing Authorization and Content-Type headers from prebuilt Request inputs when init.headers is absent, breaking authenticated requests.

1 open issue
1 file not reviewed
  • js/pnpm-lock.yaml: Generated file

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings November 9, 2026 12:19
@edewit
edewit requested a review from mposolda November 9, 2026 12:20
Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Default-on DPoP changes authentication in both consoles, but mocked transport tests do not validate proof generation, concurrent token refresh, or insecure-HTTP fallback, leaving these paths dependent on browser/server integration testing.

No open issues 🎉

1 resolved since last review
1 file not reviewed
  • js/pnpm-lock.yaml: Generated file

Review effort: Balanced

@ssilvert ssilvert left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this, Erik. The approach looks reasonable to me, but the Admin UI E2E job is failing reproducibly, so I'm requesting changes until that is sorted out.

Blocker: Admin UI E2E (chromium) fails on every completed run

All three completed runs of this PR fail with nearly the same set of tests:

Run Head Result
42007180606 5d651a7 99 failed
42207074059 ce9abb8 99 failed
42616051744 46304ef 100 failed

The same specs dominate each time: autentication/flows, users/main, realm-settings/oid4vci-attributes, client-scope/main, plus autentication/policies, autentication/policies-ciba, client-scope/mappers and sessions/sign-out. The symptom is tables and forms that never load (e.g. locator('table tbody').first() never becomes visible in flows.spec.ts:46).

This does not look inherited from main: the most recent chromium failure there is an apt/Playwright browser install error, and the run before it was green.

One pattern that may help narrow it down: the failing specs I sampled sign in with a deep link, login(page, { to: … }), while the passing ones I sampled (realm-roles/main, groups/list) use plain login(page) and navigate afterwards. I have not found the root cause — the server log artifact shows nothing relevant, and I have not gone through the Playwright trace.

Other points

  1. No real DPoP coverage. All the new tests mock fetch. Nothing asserts that a proof is actually sent or that the console token is bound. An E2E or integration check would have value here, given that this turns DPoP on by default for both consoles.

  2. Upgrade note. Once the console token is DPoP-bound, the server rejects it when presented as plain Bearer. Console extensions or custom themes that call fetch with keycloak.token directly would start getting 401s. I think this needs an entry in the upgrading guide.

  3. setConfig behaviour change in @keycloak/keycloak-admin-client. It used to reset requestOptions when the property was omitted; now it keeps the previous value, and neither requestOptions nor fetch can be cleared through it. That is probably the better behaviour, but it is a change to a public API and should be called out in the description.

  4. createKeycloakFetch rewrites any Authorization header to the console token, not only a stale console Bearer token. Fine for the current callers, but surprising for a helper exported from ui-shared. Consider limiting it to Bearer … values, or documenting the behaviour.

The earlier Copilot findings (unconverted call sites, default fetch captured at construction, missing transport tests) look addressed in the current head. The remaining raw fetch calls in QuickTheme.tsx and fetchContent.ts are unauthenticated resource loads, so they are fine as they are.

@edewit
edewit commented Nov 12, 2026
Copy link
Copy Markdown
Contributor Author

Addressed the review feedback:

Admin UI E2E blocker — root cause was keycloak-js 26.2.5 restoring the application hash after login with history.replaceState, which does not notify createHashRouter. Deep links therefore stayed on the realm welcome page (same URL in the address bar, wrong matched route). KeycloakProvider now re-applies the hash after init so the router observes it. Verified locally: previously failing deep-link specs (flows, client-scope/main, policies-ciba) pass again.

Upgrade note — documented DPoP-bound console tokens and the need for extensions to use keycloak.fetch in changes-27_0_0.adoc.

setConfig behaviour — called out in the PR description and JSDoc: omitted requestOptions/fetch keep their previous values and cannot be cleared through setConfig.

createKeycloakFetch Authorization rewrite — limited to stale Bearer headers; non-Bearer schemes (e.g. DPoP) are left unchanged.

Copilot AI balanced review requested due to automatic review settings November 12, 2026 15:48
Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The hash assignment creates a spurious Back destination and discards forward history when refreshing a deep link; the router should instead be notified with a popstate event.

1 open issue
1 file not reviewed
  • js/pnpm-lock.yaml: Generated file

Review effort: Balanced

Comment on lines +33 to +38
window.history.replaceState(
window.history.state,
"",
`${window.location.pathname}${window.location.search}`,
);
window.location.hash = hash;
edewit and others added 6 commits November 12, 2026 17:16
Use keycloak-js dpopConfig and keycloak.fetch so console API calls can
send DPoP-bound tokens when the server advertises support.

Closes keycloak#42813
Closes keycloak#42814

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
Pass adminClient.getFetch() to direct fetchWithError call sites so
Bearer-authorized admin UI helpers attach DPoP proofs when needed.

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
Avoid capturing global fetch in the admin client constructor so later
stubs still apply, and add regression coverage for constructor/setConfig
injection on v1 and v2 calls.

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
Concurrent token refreshes could make keycloak.fetch skip the Bearer→DPoP
upgrade and send DPoP-bound tokens as Bearer, breaking Admin UI E2E.

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
Refactor headers initialization to handle cases with input as Request.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Erik Jan de Wit <edewit@redhat.com>
Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
…back.

Re-apply the hash restored by keycloak-js via replaceState so createHashRouter
observes deep links, limit Authorization resync to Bearer tokens, and document
DPoP-bound console tokens plus setConfig behaviour.

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
Copilot AI balanced review requested due to automatic review settings November 12, 2026 16:18
Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Assigning location.hash after replaceState adds a hashless console entry to navigation history, causing Back to return to the console root instead of the preceding page.

1 open issue
1 file not reviewed
  • js/pnpm-lock.yaml: Generated file

Review effort: Balanced

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/account/ui Account Console — React UI for profile, sessions, security settings area/adapter/javascript JavaScript adapter (keycloak-js) — OIDC client, token management area/admin/client-js JavaScript/TypeScript admin client (@keycloak/keycloak-admin-client) area/admin/ui Admin Console — React UI for server administration area/oidc OpenID Connect / OAuth 2.0 — tokens, endpoints, scopes, DCR, PAR, DPoP

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DPoP support for the account console DPoP support for the admin console

3 participants

0