Repository navigation
docs: add Keycloak SSO setup guide - #188
gcgoncalves wants to merge 2 commits into
Conversation
7ae1160 to
67ba205
Compare
marekdano
left a comment
There was a problem hiding this comment.
1. 🔴 Functionally-impacting — Missing SSO_API_TOKEN_AUTH_ENABLED step
File: docs/sso-keycloak-setup.md, look at section 3 of this doc
The guide never says to set SSO_API_TOKEN_AUTH_ENABLED=true on the gateway. It defaults to false (mcpgateway/config.py:629). With the default, the trusted_for_api_auth admin-API step the guide describes has no effect — every proxied call returns 401. Only docs/SSO.md's section 7 mentions the flag; issue #6929 asks the guide to be sufficient on its own.
Fix: Add the flag as step 3.0, same code-block style as the PUT call; name it in a "login succeeds but every API call 401s" troubleshooting note.
2. 🔴 Functionally-impacting — Wrong provider-id guidance
File: docs/sso-keycloak-setup.md, look at section 3 of this doc
"Find the provider id (usually the realm/client slug…)" is wrong — the bootstrap hardcodes "id": "keycloak" (mcpgateway/utils/sso_bootstrap.py:268). A reader will search for a slug that doesn't exist.
Fix: State the id is keycloak; keep the GET call only as a way to confirm it.
3. 🔴 Functionally-impacting — SSO.md scope drift
File: docs/SSO.md (454 lines, whole file)
Not requested by the PR description or issue #6929, which asks only for setup docs. Quotes internals (cache TTLs, defaults, GETDEL/timingSafeEqual details) that will drift out of sync with code. Also adds 6 line-number-keyed entries to .secrets.baseline, which break on any future edit above them.
Fix: Split into its own PR with its own review, or call out the scope explicitly in the PR body; replace line-keyed baseline entries with # pragma: allowlist secret where possible, or regenerate the baseline last.
4. 🟡 Medium — PUBLIC_ORIGIN/TRUST_PROXY rule stated backwards
File: docs/sso-keycloak-setup.md — "redirect-URI gotcha"
Guide says to set PUBLIC_ORIGIN "whenever TRUST_PROXY=true," attributing this to OAUTH.md. Inverted: config.ts:238 requires PUBLIC_ORIGIN or TRUST_PROXY=true, not both — confirmed by OAUTH.md:60,389 ("or," not "and") — and index.ts:41 wires trustProxy into Fastify so request.protocol correctly follows X-Forwarded-Proto once trusted.
Fix: "Set PUBLIC_ORIGIN explicitly. Without it, the BFF derives the origin from request.protocol/request.host, which is wrong behind a proxy you do not trust with TRUST_PROXY=true."
5. 🟡 Medium — TTL-decision bullet mischaracterizes fallback
File: docs/SSO.md:291
Claims a refresh-token-less session is "capped at the access token's own expires_in." Actually establish-session.ts falls back to the full config.sessionTtlSeconds when expires_in is missing/invalid. The session does die quickly, but via a separate mechanism — tokenExpiresAt stamped at now + 0 tripping isActuallyExpired on the next request — not the one described.
6. 🟢 Minor — Trailing-slash example missing
File: docs/sso-keycloak-setup.md — "redirect-URI gotcha"
Bullet titled "Trailing slash / missing port" only shows a :443 example.
Fix: Add a trailing-slash example, or retitle the bullet.
7. 🟢 Minor — Loopback http: exception omitted
File: docs/sso-keycloak-setup.md, look at section 2 of this doc
SSO_KEYCLOAK_PUBLIC_BASE_URL row says it "Must be https://"; validateKeycloakUrl (config.ts:40) also allows http: for loopback hosts.
Fix: Add "(http: only for localhost/127.0.0.1)".
8. 🟢 Minor — Stale process narration
File: docs/sso-keycloak-setup.md, look at section 3 of this doc
"confirmed by reading the gateway's own sso_bootstrap.py" is working-process narration that will go stale.
Fix: Delete; keep only the fact that the setting is admin-API-only.
9. 🟢 Minor — Inconsistent "why a second client" rationale
File: docs/SSO.md, look at section 1 of this doc, vs sso-keycloak-setup.md "Why a second client"
"not designed to hand a session back to a third party" vs "not cross-origin-safe" — two different reasons, neither backed by a gateway reference.
Fix: Use one sentence in both places, or link a gateway doc/issue that supports the claim.
10. 🔵 Suggestion — Name required admin-token permissions
File: docs/sso-keycloak-setup.md, look at section 3 of this doc
Guide doesn't say the admin token needs admin.sso_providers:read and admin.sso_providers:update.
Fix: Add one line naming them so a non-platform-admin token doesn't fail with 403.
11. 🔵 Suggestion — No recommended api_audience
File: docs/sso-keycloak-setup.md, look at section 3 of this doc
No recommended value shown; a shared audience like mcp-gateway weakens the confused-deputy protection api_audience provides.
Fix: Recommend an audience specific to this BFF client, and show the Audience-mapper steps or link to the gateway tutorial section on them.
Document registering this BFF as its own Keycloak client (confidential, standard flow, PKCE S256), the redirect-URI exact-match gotcha, the SSO_* env vars, and the gateway-side trusted_for_api_auth/api_audience admin-API step -- which has no env var equivalent. Links to mcp-context-forge's own Keycloak tutorial for realm/role-mapper detail rather than duplicating it. Refs: IBM/mcp-context-forge#6929 Signed-off-by: Gabriel Costa <gabrielcg@proton.me>
- Add the missing SSO_API_TOKEN_AUTH_ENABLED=true gateway step (split
section 3 into 3.1/3.2); without it the trusted_for_api_auth step has
no effect and every proxied call 401s.
- Fix provider-id guidance: the gateway bootstrap hardcodes id "keycloak",
not a realm/client slug.
- Correct the PUBLIC_ORIGIN/TRUST_PROXY redirect-URI guidance: the
derived origin is already correct once TRUST_PROXY=true and the proxy
sets forwarded headers; PUBLIC_ORIGIN is for when the proxy isn't
trusted, not "whenever TRUST_PROXY=true".
- Fix SSO.md's TTL-decision bullet: a missing/invalid expires_in falls
back to the full sessionTtlSeconds, not a cap derived from the token;
tokenExpiresAt ends the session on the next request instead.
- Minor: add a trailing-slash example, note the loopback http: exception
on SSO_KEYCLOAK_PUBLIC_BASE_URL, name the admin-token permissions
needed, flag shared-audience reuse as weakening api_audience's
confused-deputy protection, remove stale sso_bootstrap.py narration,
and unify the "why a second client" wording between the two docs.
Signed-off-by: Marek Dano <mk.dano@gmail.com>
67ba205 to
33d4613
Compare
|
Pushed fixes for the review findings above (1, 2, 4–11) since Gabriel's out:
Item 3 ( |
Closes: IBM/mcp-context-forge#6929
Document registering this BFF as its own Keycloak client (confidential, standard flow, PKCE S256), the redirect-URI exact-match gotcha, the SSO_* env vars, and the gateway-side trusted_for_api_auth/api_audience admin-API step -- which has no env var equivalent. Links to mcp-context-forge's own Keycloak tutorial for realm/role-mapper detail rather than duplicating it.
Scope note:
This PR also adds
docs/SSO.md, a 454-line architecture trace of the full login/refresh/logout flow. That's broader than issue IBM/mcp-context-forge#6929asked for (setup docs only) — flagging it here rather than splitting it out post-hoc, since the two docs cross-reference each other throughout. Reviewers should treatSSO.mdas a second, independent review surface: it documents internals (cache TTLs, defaults,GETDEL/timingSafeEqualdetails) that will need upkeep as the code changes, separately from the setup guide's accuracy.