This is an automated email from the ASF dual-hosted git repository.

smolnar82 pushed a commit to branch knox_idf
in repository https://gitbox.apache.org/repos/asf/knox.git

commit 0bcb52a38b79d885463b999d35d816fc235fae05
Author: Sandor Molnar <[email protected]>
AuthorDate: Wed Aug 12 01:27:31 2026 +0200

    KNOX-3414: add Identity Federation (OIDC Provider) documentation book
    
    Add a new top-level knox-site navigation tab documenting KnoxIDF (Apache
    Knox as an OAuth2/OIDC Authorization Server), with seven chapters: Overview,
    Getting Started, Endpoint Reference, Configuration Reference, Security,
    Federation, and Operations. Enable Mermaid diagrams via pymdownx.superfences
    and add the architecture, federated-login, and consent images.
    
    Co-Authored-By: Claude Opus 4.8 <[email protected]>
---
 .../docs/assets/images/knoxidf/architecture.png    | Bin 0 -> 319038 bytes
 .../docs/assets/images/knoxidf/consent_page.png    | Bin 0 -> 87171 bytes
 .../assets/images/knoxidf/login_page_federated.png | Bin 0 -> 7329 bytes
 knox-site/docs/knoxidf/configuration.md            | 174 ++++++++++++
 knox-site/docs/knoxidf/endpoints.md                | 299 +++++++++++++++++++++
 knox-site/docs/knoxidf/federation.md               | 221 +++++++++++++++
 knox-site/docs/knoxidf/getting_started.md          | 284 +++++++++++++++++++
 knox-site/docs/knoxidf/index.md                    |  92 +++++++
 knox-site/docs/knoxidf/operations.md               | 182 +++++++++++++
 knox-site/docs/knoxidf/security.md                 | 183 +++++++++++++
 knox-site/mkdocs.yml                               |  14 +-
 11 files changed, 1448 insertions(+), 1 deletion(-)

diff --git a/knox-site/docs/assets/images/knoxidf/architecture.png 
b/knox-site/docs/assets/images/knoxidf/architecture.png
new file mode 100644
index 000000000..38294a7d4
Binary files /dev/null and 
b/knox-site/docs/assets/images/knoxidf/architecture.png differ
diff --git a/knox-site/docs/assets/images/knoxidf/consent_page.png 
b/knox-site/docs/assets/images/knoxidf/consent_page.png
new file mode 100644
index 000000000..51b552dc4
Binary files /dev/null and 
b/knox-site/docs/assets/images/knoxidf/consent_page.png differ
diff --git a/knox-site/docs/assets/images/knoxidf/login_page_federated.png 
b/knox-site/docs/assets/images/knoxidf/login_page_federated.png
new file mode 100644
index 000000000..eac3689d8
Binary files /dev/null and 
b/knox-site/docs/assets/images/knoxidf/login_page_federated.png differ
diff --git a/knox-site/docs/knoxidf/configuration.md 
b/knox-site/docs/knoxidf/configuration.md
new file mode 100644
index 000000000..a832a0bbe
--- /dev/null
+++ b/knox-site/docs/knoxidf/configuration.md
@@ -0,0 +1,174 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       https://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+# Configuration Reference
+
+KnoxIDF is configured through two layers:
+
+- **Topology `KNOXIDF` service parameters** — per-deployment behavior (token 
TTLs, consent,
+  federation, user attributes). These live inside the 
`<service><role>KNOXIDF</role>…</service>`
+  element of a topology file.
+- **`gateway-site.xml` properties** — gateway-wide concerns shared with the 
rest of Knox (signing
+  keys, persistence/database, trusted-issuer cache tuning).
+
+This chapter lists every parameter, its default, and its effect.
+
+## How KNOXIDF service parameters are read
+
+### The `knoxidf.` → `knox.token.` prefix passthrough
+
+KnoxIDF reuses Knox's existing server-managed token machinery. Any `KNOXIDF` 
service parameter
+written with the **`knoxidf.` prefix** has that prefix stripped and the 
remainder passed through
+to the underlying token configuration. So the topology parameter:
+
+```xml
+<param>
+    <name>knoxidf.knox.token.ttl</name>
+    <value>86400000</value>
+</param>
+```
+
+is delivered to the token layer as `knox.token.ttl`. This lets you set any
+[KnoxToken](../config_knox_token.md) parameter on the KnoxIDF service by 
prefixing it with
+`knoxidf.`.
+
+!!! note "Access-token TTL is managed by Knox"
+    KnoxIDF issues **server-managed** tokens: the access-token lifetime is 
governed by the token
+    layer (`knoxidf.knox.token.ttl`) and, on the token-exchange topology, by 
the `JWTProvider`'s
+    `knox.token.exp.server-managed=true`. Clients cannot request an arbitrary 
lifetime.
+
+## Core `KNOXIDF` service parameters
+
+| Parameter | Default | Description |
+|-----------|---------|-------------|
+| `knoxidf.knox.token.ttl` | (token-layer default) | Access-token lifetime in 
**milliseconds** (passthrough to `knox.token.ttl`). |
+| `knoxidf.knox.token.limit.per.user` | (token-layer default) | Max concurrent 
server-managed tokens per user; `-1` = unlimited (passthrough to 
`knox.token.limit.per.user`). |
+| `refresh.token.ttl` | `86400000` (24 h) | Refresh-token lifetime in 
milliseconds. Refresh tokens are issued only when the `offline_access` scope is 
granted, and are rotated on each use. |
+| `knoxidf.auto.consent.enabled` | `false` | When `true`, the [consent 
screen](security.md#consent) is skipped. This is a **server-side** decision and 
is never read from a client request parameter. |
+| `knoxidf.client.registration.anonymous.allowed` | `false` | When `true`, 
[dynamic client registration](security.md#dynamic-client-registration) accepts 
anonymous callers. Secure by default. |
+| `token.exchange.topology.name` | (none) | Name of the token-exchange 
topology (fronted by `JWTProvider`) to which the `token_endpoint` and 
`userinfo_endpoint` are redirected in discovery. See the [two-topology 
model](getting_started.md#3-deploy-the-knoxidf-topologies). |
+| `federated.op.names` | (none) | Comma-separated list of federated OP logical 
names to enable. See [Federated OP parameters](#federated-op-parameters). |
+
+!!! warning "Secure-by-default flags"
+    Both `knoxidf.auto.consent.enabled` and 
`knoxidf.client.registration.anonymous.allowed`
+    default to **`false`**. The sample topologies set them to `true` only to 
keep experimentation
+    frictionless — review them before any non-development deployment.
+
+## Federated OP parameters
+
+Each name listed in `federated.op.names` is configured with a block of
+`federated.op.<name>.<suffix>` parameters. See [Federation](federation.md) for 
the full flow and a
+complete example.
+
+| Suffix | Required | Default | Description |
+|--------|----------|---------|-------------|
+| `enabled` | — | `false` | Activates this OP. Only enabled OPs are offered on 
the login page. |
+| `issuer` | **Yes** | — | Expected `iss` of the OP's id_token. Validated 
exactly — must match the OP's issuer. |
+| `jwks.endpoint` | **Yes** | — | OP JWKS URL used to verify the id_token 
signature. |
+| `clientId` | Yes | — | Knox's client id at the OP; must appear in the 
id_token `aud`. |
+| `clientSecret` | Conditional | — | Knox's client secret at the OP 
(plaintext). Prefer `clientSecret.alias`. |
+| `clientSecret.alias` | Conditional | — | Alias name resolved via 
`AliasService`. **Takes precedence** over `clientSecret` and **fails closed** 
if unresolvable. See [Security → Secret handling](security.md#secret-handling). 
|
+| `authorize.endpoint` | Yes | — | OP authorization endpoint Knox redirects 
the user to. |
+| `token.endpoint` | Yes | — | OP token endpoint for the back-channel code 
exchange. |
+| `userinfo.endpoint` | No | — | OP UserInfo endpoint. |
+| `discovery.endpoint` | No | — | OP discovery document URL (alternative to 
listing endpoints individually). |
+| `authorize.callback` | Yes | — | The Knox callback URL registered at the OP 
(`…/knoxidf/api/v1/authorize/callback`). |
+| `signature.algorithm` | No | `RS256` | Expected id_token signing algorithm. |
+
+## User parameters and claims
+
+KnoxIDF can enrich issued tokens with additional claims — statically 
configured claims and, for
+local users, attributes resolved from a **user-parameter provider**.
+
+### Hard-coded claim mappings
+
+| Parameter | Default | Description |
+|-----------|---------|-------------|
+| `knox.token.hardcoded.claim.mappings` | (none) | `;`-separated list of 
`key=value` pairs added as claims to every issued token. |
+
+### LDAP user-parameter provider
+
+If `user.params.provider.ldap.url` is set, KnoxIDF looks up the authenticated 
user in LDAP and adds
+the resolved attributes to the token (and to the UserInfo response). If it is 
**absent**, an
+`EmptyUserParamsProvider` is used and no LDAP lookup occurs.
+
+| Parameter | Default | Description |
+|-----------|---------|-------------|
+| `user.params.provider.ldap.url` | (none) | LDAP(S) URL. Its presence selects 
the LDAP provider; absence selects the no-op provider. |
+| `user.params.provider.ldap.baseDn` | `dc=hadoop,dc=apache,dc=org` | Search 
base DN. |
+| `user.params.provider.ldap.userDnTemplate` | 
`uid=%s,ou=people,dc=hadoop,dc=apache,dc=org` | DN template; `%s` is replaced 
with the (escaped) username. |
+| `user.params.provider.ldap.systemUser` | 
`uid=admin,ou=people,dc=hadoop,dc=apache,dc=org` | Bind DN for attribute 
lookups. |
+| `user.params.provider.ldap.systemPasswordAlias` | — | **Required** alias for 
the system-user password. There is no plaintext fallback — if the alias is 
absent or unresolvable, initialization fails with an `IllegalStateException` 
(fail-closed). |
+
+## Gateway-site properties
+
+These are set in `$KNOX_HOME/conf/gateway-site.xml` and shared with the rest 
of Knox.
+
+### Signing keys
+
+| Property | Default | Description |
+|----------|---------|-------------|
+| `gateway.signing.key.alias` | `gateway-identity` | Alias of the primary key 
used to sign KnoxIDF-issued JWTs. |
+| `gateway.signing.key.aliases.additional` | `none` | Comma-separated 
additional signing-key aliases to **also publish** on the JWKS endpoint. This 
is the mechanism behind zero-downtime [signing-key 
rotation](operations.md#signing-key-rotation). `none` means no additional keys. 
|
+| `gateway.signing.keystore.name` | (gateway identity keystore) | Keystore 
holding the signing key(s). |
+| `gateway.signing.keystore.type` | (gateway default) | Keystore type (e.g. 
`JKS`, `PKCS12`). |
+| `gateway.signing.keystore.password.alias` | (gateway default) | Alias of the 
keystore password. |
+
+### Persistence and database
+
+KnoxIDF's [federated-identity 
store](operations.md#federated-identity-persistence) and the trusted-issuer
+registry share Knox's database configuration. With no external database 
configured, KnoxIDF
+self-provisions an **embedded Derby** database (the same physical store used 
by token state), so no
+setup is required to get started.
+
+| Property | Default | Description |
+|----------|---------|-------------|
+| `gateway.database.type` | `none` | Database backend: `none` / `derbydb` 
select the embedded self-provisioning Derby store; a real external type 
(`postgresql`, `mysql`, `oracle`, …) selects the JDBC-backed store. |
+| `gateway.database.connection.url` | (none) | Full JDBC URL (overrides 
host/port/name if set). |
+| `gateway.database.host` | (none) | Database host (when not using a full 
connection URL). |
+| `gateway.database.port` | (none) | Database port. |
+| `gateway.database.name` | `GATEWAY_DATABASE` | Database/schema name. |
+| `gateway.database.ssl.enabled` | `false` | Enable TLS to the database. |
+| `gateway.database.ssl.truststore.path` / `.alias` | (none) | Truststore path 
/ password alias for the database TLS connection. |
+
+Database credentials are supplied as aliases (`gateway_database_user`,
+`gateway_database_password`) — see [Getting 
Started](getting_started.md#2-install-and-start-knox).
+
+### Trusted OIDC issuer registry
+
+| Property | Default | Description |
+|----------|---------|-------------|
+| `gateway.trustedoidcissuer.discovery.cache.ttl.secs` | `600` | How long a 
fetched issuer JWKS/discovery document is cached before re-fetch. |
+| `gateway.trustedoidcissuer.discovery.connect.timeout.ms` | `3000` | Connect 
timeout when fetching an issuer's discovery/JWKS document. |
+| `gateway.trustedoidcissuer.discovery.read.timeout.ms` | `10000` | Read 
timeout for the same fetch. |
+| `gateway.trusted.oidc.issuer.max.issuers` | `10000` | Upper bound on the 
number of registered trusted issuers. Registration returns `409 
issuer_limit_reached` once reached. |
+
+### Provider-related properties (sample topologies)
+
+These are not KnoxIDF parameters but appear in the sample federation 
topologies:
+
+| Property | Description |
+|----------|-------------|
+| `jwt.expected.issuer` | Expected issuer enforced by a `JWTProvider` fronting 
the token-exchange topology. |
+| `sso.unauthenticated.path.list` | On an `SSOCookieProvider` front topology, 
the `;`-separated list of KnoxIDF paths reachable before login (callback, JWKS, 
discovery, registration). See 
[Federation](federation.md#front-topology-for-federation). |
+
+## See also
+
+- [Getting Started](getting_started.md) — worked topology examples.
+- [Security](security.md) — what the secure-by-default flags protect against.
+- [Federation](federation.md) — configuring external OPs.
+- [Operations](operations.md) — persistence backends and signing-key rotation.
diff --git a/knox-site/docs/knoxidf/endpoints.md 
b/knox-site/docs/knoxidf/endpoints.md
new file mode 100644
index 000000000..c3c5f14fb
--- /dev/null
+++ b/knox-site/docs/knoxidf/endpoints.md
@@ -0,0 +1,299 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       https://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+# Endpoint Reference
+
+KnoxIDF exposes a set of REST endpoints aligned with the standard OpenID 
Connect expectations,
+so clients configured for a Keycloak-like provider work against Knox with 
minimal changes.
+
+## Base path and URL structure
+
+All KnoxIDF endpoints share the base path `knoxidf/api/v1`. As with every Knox 
service, the
+gateway prefixes the topology name, so a fully-qualified URL looks like:
+
+```
+https://{knox-host}:8443/gateway/{topology}/knoxidf/api/v1/{endpoint}
+```
+
+The administrative endpoints (service role `KNOXIDF_ADMIN`) live under a 
separate base path,
+`knoxidf/admin/v1`.
+
+!!! tip "Always read endpoint URLs from discovery"
+    Do not hard-code endpoint paths in clients. Fetch the
+    [discovery document](#discovery-endpoint) and use the URLs it advertises. 
When a
+    `token.exchange.topology.name` is configured, the `token_endpoint` and 
`userinfo_endpoint`
+    are deliberately rewritten to point at the token-exchange topology — 
discovery reflects
+    that, hard-coded paths will not.
+
+## Endpoint summary
+
+| Endpoint | Path | Methods | Role |
+|----------|------|---------|------|
+| [Discovery](#discovery-endpoint) | 
`knoxidf/api/v1/.well-known/openid-configuration` | GET | `KNOXIDF` |
+| [Authorization](#authorization-endpoint) | `knoxidf/api/v1/authorize` | GET, 
POST | `KNOXIDF` |
+| [Federated callback](#federated-callback) | 
`knoxidf/api/v1/authorize/callback` | GET | `KNOXIDF` |
+| [Token](#token-endpoint) | `knoxidf/api/v1/token` | POST | `KNOXIDF` |
+| [UserInfo](#userinfo-endpoint) | `knoxidf/api/v1/userinfo` | GET | `KNOXIDF` 
|
+| [JWKS](#jwks-endpoint) | `knoxidf/api/v1/jwks` | GET | `KNOXIDF` |
+| [Client Registration](#client-registration-endpoint) | 
`knoxidf/api/v1/client/register` | POST | `KNOXIDF` |
+| [Consent page](#consent-page) | `authConsent` | GET, POST | `KNOXIDF` |
+| [Trusted OIDC Issuers (admin)](#trusted-oidc-issuers-admin) | 
`knoxidf/admin/v1/trusted-oidc-issuers` | GET, POST, DELETE | `KNOXIDF_ADMIN` |
+
+---
+
+## Discovery endpoint
+
+`GET /knoxidf/api/v1/.well-known/openid-configuration`
+
+Returns the OpenID Connect Discovery document. All endpoint URLs are built 
dynamically from the
+request's base URI, so the document is always correct for the topology it is 
served from.
+
+Example document:
+
+```json
+{
+  "issuer": "https://knox:8443/gateway/knoxidf-ldap/knoxidf";,
+  "authorization_endpoint": 
"https://knox:8443/gateway/knoxidf-ldap/knoxidf/api/v1/authorize";,
+  "token_endpoint": 
"https://knox:8443/gateway/knoxidf-token/knoxidf/api/v1/token";,
+  "userinfo_endpoint": 
"https://knox:8443/gateway/knoxidf-token/knoxidf/api/v1/userinfo";,
+  "registration_endpoint": 
"https://knox:8443/gateway/knoxidf-ldap/knoxidf/api/v1/client";,
+  "jwks_uri": "https://knox:8443/gateway/knoxidf-ldap/knoxidf/api/v1/jwks";,
+  "response_types_supported": ["code"],
+  "subject_types_supported": ["public"],
+  "token_endpoint_auth_methods_supported": ["client_secret_post", "none"],
+  "client_id_metadata_document_supported": false,
+  "grant_types_supported": ["authorization_code", "refresh_token"],
+  "scopes_supported": ["openid", "profile", "email", "offline_access"],
+  "id_token_signing_alg_values_supported": ["RS256"],
+  "code_challenge_methods_supported": ["S256"]
+}
+```
+
+Notable metadata:
+
+- **`subject_types_supported: ["public"]`** — Knox derives a shared 
(non-pairwise) `sub`, the
+  same value for every client.
+- **`token_endpoint_auth_methods_supported: ["client_secret_post", "none"]`** 
— the token
+  endpoint reads client credentials only from the request body 
(`client_secret_post`);
+  public clients use PKCE with no secret (`none`). HTTP Basic 
(`client_secret_basic`) is
+  intentionally **not** advertised because it is not honored.
+- **`code_challenge_methods_supported: ["S256"]`** — only S256 PKCE is 
accepted; `plain` is
+  rejected.
+- **`client_id_metadata_document_supported: false`** — Knox does not resolve a 
URL-style
+  `client_id` as a Client ID Metadata Document (OAuth CIMD draft, referenced 
by the MCP
+  authorization spec); clients must use dynamic registration instead.
+
+---
+
+## Authorization endpoint
+
+`GET|POST /knoxidf/api/v1/authorize`
+
+Begins the Authorization Code flow. Validates the request, checks (or 
collects) user consent,
+and redirects back to the client `redirect_uri` with an authorization `code` 
and the echoed
+`state`. If consent has not yet been granted for this (user, client, scopes), 
the browser is
+first redirected to the [consent page](#consent-page).
+
+Request parameters:
+
+| Parameter | Required | Description |
+|-----------|----------|-------------|
+| `response_type` | Yes | `code`, `id_token`, or `code id_token`. |
+| `client_id` | Yes | A registered client identifier. |
+| `redirect_uri` | Yes | Must match the client's registered `redirect_uris`. |
+| `scope` | No | Space-delimited scopes. Defaults to `openid profile email 
offline_access`. |
+| `state` | No | Opaque CSRF value, echoed back in the redirect. |
+| `nonce` | No | Bound to the issued ID token. |
+| `code_challenge` | No (PKCE) | Base64url S256 hash of the `code_verifier`. |
+| `code_challenge_method` | Required if `code_challenge` present | Must be 
`S256`; `plain` is rejected. |
+
+**Success:** `302` redirect to `{redirect_uri}?code={auth_code}&state={state}`.
+
+**Errors:** a JSON body `{"error": "...", "error_description": "..."}` — 
`invalid_request`
+(unknown `client_id`, bad `redirect_uri`, missing parameters, unsupported PKCE 
method) or
+`invalid_scope` (a requested scope is not in the client's allowed scopes). 
When consent is
+required, a `303` redirect to the consent page.
+
+### Federated callback
+
+`GET /knoxidf/api/v1/authorize/callback`
+
+Back-channel callback invoked by an external OIDC Provider during 
[federation](federation.md).
+Exchanges the OP authorization `code` for the OP's tokens, **validates the OP 
`id_token`**
+(signature via JWKS, issuer, audience, nonce, and `sub` presence), resolves or 
persists the
+federated identity, then issues a Knox authorization code and redirects to the 
original client
+`redirect_uri`.
+
+| Parameter | Required | Description |
+|-----------|----------|-------------|
+| `code` | Yes | Authorization code from the federated OP. |
+| `state` | Yes | Must match a live entry in the authorize-request store. |
+
+This endpoint must be reachable without prior Knox authentication (wired as 
`anon`, or listed
+in `sso.unauthenticated.path.list`).
+
+---
+
+## Token endpoint
+
+`POST /knoxidf/api/v1/token` &nbsp; `Content-Type: 
application/x-www-form-urlencoded`
+
+Issues tokens. Supports the **Client Credentials**, **Authorization Code**, 
and **Refresh
+Token** grants. Client authentication is enforced here — see
+[Security](security.md#token-endpoint-client-authentication).
+
+### Authorization Code grant
+
+Redeems a one-time authorization code. The code is atomically consumed 
(single-use); a public
+client proves possession via PKCE `code_verifier`, a confidential client via 
`client_secret`.
+
+| Parameter | Required | Description |
+|-----------|----------|-------------|
+| `grant_type` | Yes | `authorization_code`. |
+| `code` | Yes | The authorization code from `/authorize`. |
+| `redirect_uri` | Yes | Must match the URI stored with the code. |
+| `client_id` | Yes | Must match the client that obtained the code. |
+| `client_secret` | Conditional | Required when no `code_challenge` was 
stored. |
+| `code_verifier` | Conditional | Required when a `code_challenge` was stored 
at authorize time. |
+
+### Refresh Token grant
+
+Rotates a refresh token: atomically consumes the presented token and issues a 
new
+access-token / refresh-token pair. Requires `client_secret`.
+
+| Parameter | Required | Description |
+|-----------|----------|-------------|
+| `grant_type` | Yes | `refresh_token`. |
+| `refresh_token` | Yes | A previously issued refresh token. |
+| `client_id` | Yes | Must match the client bound to the refresh token. |
+| `client_secret` | Yes | Client secret. |
+
+**Success (`200`):**
+
+```json
+{
+  "access_token": "<JWT>",
+  "token_id": "<UUID>",
+  "token_type": "Bearer",
+  "expires_in": 1699999999999,
+  "managed_token": "true",
+  "id_token": "<JWT>",
+  "refresh_token": "<JWT>",
+  "passcode": "<Base64(tokenId)::Base64(passcode)>"
+}
+```
+
+`refresh_token` is present only when the scope includes `offline_access`. The 
`id_token`
+carries `sub`, `iss`, `aud` (= `client_id`), `exp`, `iat`, and `nonce` (when 
supplied); for
+federated users it additionally carries `federated_idp`, `federated_sub`, and 
`federated_iss`
+plus any allowed profile claims (`preferred_username`, `email`, 
`email_verified`,
+`given_name`, `family_name`, `name`, `locale`).
+
+**Errors:** `invalid_grant` (missing/expired/replayed code, `redirect_uri` or 
`client_id`
+mismatch, PKCE failure, bad `client_secret`, disabled/expired refresh token) or
+`invalid_request` (unsupported `grant_type`).
+
+---
+
+## UserInfo endpoint
+
+`GET /knoxidf/api/v1/userinfo`
+
+Returns OIDC UserInfo claims for a valid bearer access token. The upstream 
`JWTProvider`
+validates the token and hands the token identity to this resource; the 
endpoint never reads the
+raw `Authorization` header itself. For a federated user it returns the 
internal Knox `sub`, the
+`idp` name, `federated_sub`, `federated_iss`, and any allowed profile claims; 
for a local user
+it returns whatever the configured [user-parameter 
provider](configuration.md#user-parameters-and-claims)
+resolves.
+
+**Errors:** `invalid_request` when no token identity is present; `401` with
+`WWW-Authenticate: Bearer error="invalid_token"` for an expired, revoked, or 
unknown token.
+
+---
+
+## JWKS endpoint
+
+`GET /knoxidf/api/v1/jwks`
+
+Publishes the gateway's public signing key(s) as a JWK Set so clients and 
resource servers can
+verify KnoxIDF-issued JWTs. One JWK is published per configured signing-key 
alias, each keyed by
+the SHA-256 thumbprint of its public key as the `kid`. This is what makes 
signing-key rotation
+transparent to verifiers — see [Operations → Signing-key 
rotation](operations.md#signing-key-rotation).
+
+```json
+{
+  "keys": [
+    { "kty": "RSA", "use": "sig", "alg": "RS256", "kid": "<sha-256 
thumbprint>", "n": "...", "e": "AQAB" }
+  ]
+}
+```
+
+---
+
+## Client Registration endpoint
+
+`POST /knoxidf/api/v1/client/register` &nbsp; `Content-Type: 
application/x-www-form-urlencoded`
+
+Dynamically registers an OAuth2 client and returns a `client_id` and 
`client_secret`. Redirect
+URIs must use HTTPS (plain HTTP is allowed only for loopback hosts, per RFC 
8252). Anonymous
+registration is **refused by default** and only permitted when
+`knoxidf.client.registration.anonymous.allowed=true` is set on the topology — 
see
+[Security](security.md#dynamic-client-registration).
+
+| Parameter | Required | Description |
+|-----------|----------|-------------|
+| `redirect_uris` | Yes | Comma-separated. HTTPS required (loopback HTTP 
allowed); a wildcard `*` is only permitted at the end of the path, never in the 
host. |
+| `allowed_scopes` | No | Comma-separated; must include `openid`. Defaults to 
`openid,profile,email,offline_access`. |
+
+**Success (`200`):** returns `token_id` (the `client_id`), `passcode` (the 
`client_secret` to
+use on `/token`), and the stored `redirect_uris` and `allowed_scopes`.
+
+**Errors:** `access_denied` (anonymous caller when disabled), 
`invalid_request` (missing/invalid
+`redirect_uris`, wrong scheme), `invalid_scope` (`allowed_scopes` omits 
`openid`).
+
+---
+
+## Consent page
+
+`GET|POST /{topology}/authConsent`
+
+An HTML consent page (a lightweight servlet, registered only when the topology 
includes the
+`KNOXIDF` service). `GET` renders the requesting `client_id` and a 
human-readable description of
+each requested scope with **Accept** / **Deny** buttons. `POST` records the 
decision and
+redirects to `authorize/consentAccepted` (issues the code) or 
`authorize/consentDenied`
+(`403`). Consent is one-time per (user, client, scopes) — see
+[Security → Consent](security.md#consent).
+
+![The KnoxIDF consent page: "Application Consent Required", listing the 
requesting client and the scopes it will be granted, with Accept and Deny 
buttons.](../assets/images/knoxidf/consent_page.png)
+
+---
+
+## Trusted OIDC Issuers (admin)
+
+Base path `knoxidf/admin/v1/trusted-oidc-issuers`, served by the 
`KNOXIDF_ADMIN` service role
+(a separate, administrator-only topology). Manages the set of external issuers 
whose `id_token`s
+Knox will accept during federated login.
+
+| Method | Path | Purpose | Success |
+|--------|------|---------|---------|
+| `POST` | `/trusted-oidc-issuers` | Register a trusted issuer (JSON body: 
`issuerUrl` (HTTPS, required), `dynamicJwks`, `clusterName`). | `201` |
+| `GET` | `/trusted-oidc-issuers` | List registered issuers (with 
`registeredAt` / `registeredBy`). | `200` |
+| `DELETE` | `/trusted-oidc-issuers?issuerUrl=...` | Deregister an issuer 
(idempotent). | `204` |
+| `POST` | `/trusted-oidc-issuers/refresh-jwks?issuerUrl=...` | Force a JWKS 
cache refresh for a `dynamicJwks` issuer. | `204` |
+
+**Errors:** `400 invalid_request` (missing/non-HTTPS `issuerUrl`, malformed 
JSON),
+`409 issuer_exists`, `409 issuer_limit_reached` (issuer cap), `500 
storage_error`.
diff --git a/knox-site/docs/knoxidf/federation.md 
b/knox-site/docs/knoxidf/federation.md
new file mode 100644
index 000000000..ad17d74c6
--- /dev/null
+++ b/knox-site/docs/knoxidf/federation.md
@@ -0,0 +1,221 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       https://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+# Federation
+
+In addition to being a standalone OIDC Provider, KnoxIDF can **broker** login 
to one or more
+external OpenID Providers (OPs) — Keycloak, Okta, Azure AD, Auth0, and so on. 
In this mode Knox
+delegates the actual authentication to the external OP, validates the identity 
it returns, and
+then re-issues **its own Knox-signed tokens** to the client. Downstream 
services still only need
+to trust Knox, regardless of where the user actually authenticated.
+
+Federation is entirely optional and configured per topology. A topology with no
+`federated.op.names` behaves as a pure Knox OP.
+
+## The login experience
+
+When a topology fronts `/authorize` with an SSO cookie provider and has one or 
more federated
+OPs enabled, the Knox login page offers the external OP as an alternative to 
Knox's own
+authentication providers (LDAP, PAM, SAML, Kerberos, …):
+
+![The Knox login page showing username/password fields and a "Continue with 
KeyCloak" button below an "Or" 
separator.](../assets/images/knoxidf/login_page_federated.png)
+
+The end user chooses whether to sign in with a Knox-native provider or to 
identify themselves
+through the external OIDC Provider.
+
+## Broker flow
+
+Federation is implemented as a token-brokering mechanism:
+
+```mermaid
+sequenceDiagram
+    autonumber
+    participant Client
+    participant Knox as Knox (KnoxIDF)
+    participant OP as External OP
+    Client->>Knox: GET /authorize (response_type=code, PKCE)
+    Note over Knox: Authenticate request, validate params, check consent
+    Knox->>OP: Redirect to OP /authorize (nonce, callback)
+    OP-->>Client: Prompt for login
+    Client->>OP: Authenticate
+    OP->>Knox: GET /authorize/callback (code, state)
+    Note over Knox: Exchange code at OP /token (back-channel)
+    Knox->>OP: POST /token (federated code, client_secret)
+    OP-->>Knox: OP tokens (id_token)
+    Note over Knox: Validate id_token (sig via JWKS, iss, aud, nonce, sub)
+    Note over Knox: Resolve / persist federated identity
+    Knox-->>Client: Redirect to redirect_uri (Knox code, state)
+    Client->>Knox: POST /token (code + client_secret / code_verifier)
+    Knox-->>Client: Knox access_token + id_token (+ refresh_token)
+```
+
+Step by step:
+
+1. **Client initiates.** The OIDC client calls `/authorize`. The topology's 
provider
+   authenticates the request and Knox validates the parameters and checks 
consent.
+2. **Delegate to the OP.** With a federated OP enabled, Knox builds an 
authorization redirect to
+   the OP's `authorize.endpoint`, including a freshly generated `nonce` 
(stored server-side for
+   this session) and the callback URL `/knoxidf/api/v1/authorize/callback`.
+3. **The OP authenticates the user** and redirects back to Knox's callback 
with an authorization
+   `code` and the `state`.
+4. **Back-channel token exchange.** Knox exchanges the OP code at the OP's 
`token.endpoint`,
+   resolving the OP `client_secret` (from an 
[alias](security.md#secret-handling) if configured).
+5. **Validate the OP `id_token`.** Knox verifies the signature (via the OP's 
JWKS), the issuer,
+   the audience, the `nonce`, and the presence of `sub` — see
+   [Security → Federated id_token 
validation](security.md#federated-id_token-validation). Nothing
+   in the token is trusted before this passes.
+6. **Resolve or persist the federated identity.** Knox looks up `(provider, 
issuer, subject)`;
+   if not found, it persists a new federated identity, deriving a stable Knox 
`sub` as a
+   [UUIDv5](security.md#subject-derivation) over the OP issuer and subject.
+7. **Issue a Knox authorization code**, then redirect the client to its 
`redirect_uri`.
+8. **Client redeems the code** at Knox's `/token` endpoint (with PKCE or 
`client_secret`) and
+   receives Knox-signed tokens whose `id_token` carries the federated claims 
below.
+
+## Federated claims in the Knox id_token
+
+For a federated user, the Knox-issued `id_token` (and the UserInfo response) 
carry the origin of
+the identity alongside the Knox subject:
+
+| Claim | Meaning | Example |
+|-------|---------|---------|
+| `sub` | Stable Knox subject (UUIDv5 over issuer + external subject). | 
`f47ac10b-58cc-45c8-...` |
+| `federated_idp` | The federated provider name, **upper-cased**. | `KEYCLOAK` 
|
+| `federated_sub` | The `sub` from the OP's id_token. | `248289761001` |
+| `federated_iss` | The `iss` from the OP's id_token. | 
`https://op.example/realms/knox` |
+
+Allowed profile claims (`preferred_username`, `email`, `email_verified`, 
`given_name`,
+`family_name`, `name`, `locale`) are included when present. The UserInfo 
response uses `idp` for
+the provider name (also upper-cased) in place of `federated_idp`.
+
+!!! note
+    Because `federated_idp` and the stored provider are upper-cased, a 
configured OP name of
+    `keycloak` appears in tokens as `KEYCLOAK`. Match on the upper-cased value 
in downstream
+    authorization logic.
+
+## Configuring a federated OP
+
+Federated OPs are declared as `KNOXIDF` service parameters so they are exposed 
as servlet
+context init-params (read by both `AuthorizeResource` and the SSO cookie 
federation filter in
+the same webapp). First list the OP logical names, then provide a block of
+`federated.op.<name>.*` parameters for each. The example below is the tested 
CI topology for a
+Keycloak OP:
+
+```xml
+<service>
+    <role>KNOXIDF</role>
+    <!-- ... core KnoxIDF params (ttl, consent, token-exchange topology) ... 
-->
+
+    <param>
+        <name>federated.op.names</name>
+        <value>keycloak</value>
+    </param>
+    <param>
+        <name>federated.op.keycloak.enabled</name>
+        <value>true</value>
+    </param>
+    <param>
+        <name>federated.op.keycloak.clientId</name>
+        <value>knox-client</value>
+    </param>
+    <param>
+        <name>federated.op.keycloak.clientSecret</name>
+        <value>knox-client-secret</value>
+    </param>
+    <param>
+        <name>federated.op.keycloak.authorize.endpoint</name>
+        
<value>http://keycloak:8080/realms/knox/protocol/openid-connect/auth</value>
+    </param>
+    <param>
+        <name>federated.op.keycloak.authorize.callback</name>
+        
<value>https://knox:8443/gateway/knoxidf-sso/knoxidf/api/v1/authorize/callback</value>
+    </param>
+    <param>
+        <name>federated.op.keycloak.token.endpoint</name>
+        
<value>http://keycloak:8080/realms/knox/protocol/openid-connect/token</value>
+    </param>
+    <param>
+        <name>federated.op.keycloak.jwks.endpoint</name>
+        
<value>http://keycloak:8080/realms/knox/protocol/openid-connect/certs</value>
+    </param>
+    <param>
+        <name>federated.op.keycloak.issuer</name>
+        <value>http://keycloak:8080/realms/knox</value>
+    </param>
+    <param>
+        <name>federated.op.keycloak.userinfo.endpoint</name>
+        
<value>http://keycloak:8080/realms/knox/protocol/openid-connect/userinfo</value>
+    </param>
+    <param>
+        <name>federated.op.keycloak.signature.algorithm</name>
+        <value>RS256</value>
+    </param>
+</service>
+```
+
+!!! warning "Prefer an alias for the OP client secret"
+    The example above uses a plaintext `clientSecret` for brevity. In 
production, store the
+    secret in Knox's credential store and reference it with
+    `federated.op.keycloak.clientSecret.alias` instead — the alias takes 
precedence and
+    resolution fails closed if it cannot be resolved. See
+    [Security → Secret handling](security.md#secret-handling). See the
+    [Configuration Reference](configuration.md#federated-op-parameters) for 
every
+    `federated.op.<name>.*` parameter.
+
+### Front topology for federation
+
+The federation login experience requires a topology that fronts `/authorize` 
with an
+`SSOCookieProvider` (so an unauthenticated `/authorize` is redirected to the 
Knox login
+front-end), with the federation callback and other pre-login endpoints listed 
in
+`sso.unauthenticated.path.list`:
+
+```xml
+<provider>
+    <role>federation</role>
+    <name>SSOCookieProvider</name>
+    <enabled>true</enabled>
+    <param>
+        <name>sso.authentication.provider.url</name>
+        <value>https://knox:8443/gateway/knoxsso/api/v1/websso</value>
+    </param>
+    <param>
+        <name>sso.unauthenticated.path.list</name>
+        
<value>/knoxidf/api/v1/authorize/callback;/knoxidf/api/v1/jwks;/knoxidf/api/v1/.well-known/openid-configuration;/knoxidf/api/v1/client/register</value>
+    </param>
+</provider>
+```
+
+## Multiple OPs
+
+`federated.op.names` accepts a comma-separated list, and each named OP gets 
its own
+`federated.op.<name>.*` block. Only OPs with `enabled=true` are activated; the 
login page offers
+each enabled OP as a separate sign-in option.
+
+## Trusted issuer registry
+
+The external issuers whose tokens Knox will accept are administered through the
+[Trusted OIDC Issuers admin API](endpoints.md#trusted-oidc-issuers-admin), 
served by the
+`KNOXIDF_ADMIN` role on an administrator-restricted topology. Issuer JWKS 
documents are cached
+(`gateway.trustedoidcissuer.discovery.cache.ttl.secs`, default 600s); the 
admin API's
+`refresh-jwks` action forces an immediate re-fetch for issuers configured with 
dynamic JWKS.
+
+## Persistence
+
+Federated identities are persisted so the same upstream user maps to a stable 
Knox subject and
+so their attributes can be reused. This store activates automatically when a 
`KNOXIDF` (or
+`KNOXIDF_ADMIN`) topology is present — no explicit configuration is required. 
See
+[Operations → Federated identity 
persistence](operations.md#federated-identity-persistence) for
+the backend-selection rules and how to point KnoxIDF at an external database.
diff --git a/knox-site/docs/knoxidf/getting_started.md 
b/knox-site/docs/knoxidf/getting_started.md
new file mode 100644
index 000000000..7b17ff19c
--- /dev/null
+++ b/knox-site/docs/knoxidf/getting_started.md
@@ -0,0 +1,284 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       https://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+# Getting Started
+
+This chapter walks through building Knox with KnoxIDF, deploying the 
topologies that expose
+the OIDC endpoints, registering a client, and running a first Client 
Credentials flow.
+
+!!! note "Branch"
+    At the time of writing, KnoxIDF lives on the `knox_idf` development branch 
(kept in sync
+    with `master`). Build from that branch until it is merged.
+
+## 1. Build Knox
+
+```bash
+git clone https://github.com/apache/knox.git
+cd knox
+git checkout knox_idf
+
+mvn -DskipTests -Dcheckstyle.skip=true -Dfindbugs.skip=true -Dpmd.skip=true \
+    -Drat.skip -Dspotbugs.skip=true -Dforbiddenapis.skip=true \
+    -Ppackage clean install
+```
+
+The build produces a Knox distribution archive under
+`gateway-release/target/{version}/knox-{version}.zip`.
+
+## 2. Install and start Knox
+
+Unzip the distribution into a deployment directory (`$KNOX_HOME`), create the 
master secret
+and the required aliases, then start the gateway. The signing-key hash alias
+(`knox.token.hash.key`) backs server-managed (passcode) tokens; the database 
aliases back the
+embedded/external persistence used by KnoxIDF and token state.
+
+```bash
+export KNOX_HOME=/path/to/knoxGateway
+
+# Master secret (non-interactive)
+$KNOX_HOME/bin/knoxcli.sh create-master --master gateway
+
+# Signing / passcode HMAC key
+$KNOX_HOME/bin/knoxcli.sh create-alias knox.token.hash.key --value 
<a-strong-random-secret>
+
+# Database credential aliases (used by the embedded Derby store and any 
external DB)
+$KNOX_HOME/bin/knoxcli.sh create-alias gateway_database_user --value knox
+$KNOX_HOME/bin/knoxcli.sh create-alias gateway_database_password --value knox
+
+$KNOX_HOME/bin/gateway.sh start
+```
+
+!!! tip "Local (non-TLS) testing"
+    For local experimentation you can disable TLS by setting 
`ssl.enabled=false` in
+    `$KNOX_HOME/conf/gateway-site.xml`. **Do not do this in production** — 
OAuth 2.0 / OIDC
+    requires TLS for all token-bearing traffic.
+
+By default, KnoxIDF's federated-identity persistence uses an **embedded 
Derby** database that
+Knox provisions automatically (the same physical DB used by token state). No 
external database
+is required to get started. To point KnoxIDF at an external database 
(PostgreSQL, etc.), see
+the [Configuration Reference](configuration.md) and 
[Operations](operations.md) chapters.
+
+## 3. Deploy the KnoxIDF topologies
+
+A typical KnoxIDF deployment uses **two topologies**:
+
+- **A "front" topology** that exposes the OIDC endpoints and authenticates the 
end user (for
+  example with LDAP Basic auth, or with an SSO cookie provider for 
federation). This is where
+  `/authorize`, `/client/register`, `/jwks`, and discovery live.
+- **A "token" topology** fronted by Knox's `JWTProvider`, referenced by the 
front topology's
+  `token.exchange.topology.name`. The `/token` exchange is redirected here so 
that redeeming an
+  authorization code is authenticated by a Knox-issued JWT.
+
+Copy the topology files into `$KNOX_HOME/conf/topologies/`; Knox hot-deploys 
them within a few
+seconds.
+
+### Front topology (LDAP Basic auth) — `knoxidf-ldap.xml`
+
+The `ShiroProvider` authenticates users against LDAP, and the OIDC endpoints 
that must be
+reachable *before* login (discovery, registration, JWKS, and the federation 
callback) are
+wired as `anon`:
+
+```xml
+<topology>
+    <gateway>
+      <provider>
+         <role>authentication</role>
+         <name>ShiroProvider</name>
+         <enabled>true</enabled>
+         <param>
+            <name>main.ldapRealm</name>
+            <value>org.apache.knox.gateway.shirorealm.KnoxLdapRealm</value>
+         </param>
+         <param>
+            <name>main.ldapRealm.userDnTemplate</name>
+            <value>uid={0},ou=people,dc=hadoop,dc=apache,dc=org</value>
+         </param>
+         <param>
+            <name>main.ldapRealm.contextFactory.url</name>
+            <value>ldaps://localhost:33390</value>
+         </param>
+         <param>
+            <name>main.ldapRealm.contextFactory.authenticationMechanism</name>
+            <value>simple</value>
+         </param>
+         <param>
+            <name>urls./knoxidf/api/v1/.well-known/openid-configuration</name>
+            <value>anon</value>
+         </param>
+         <param>
+            <name>urls./knoxidf/api/v1/client/register</name>
+            <value>anon</value>
+         </param>
+         <param>
+            <name>urls./knoxidf/api/v1/authorize/callback</name>
+            <value>anon</value>
+         </param>
+         <param>
+            <name>urls./knoxidf/api/v1/jwks</name>
+            <value>anon</value>
+          </param>
+         <param>
+            <name>urls./**</name>
+            <value>authcBasic</value>
+         </param>
+      </provider>
+      <provider>
+            <role>identity-assertion</role>
+            <name>Default</name>
+            <enabled>true</enabled>
+      </provider>
+    </gateway>
+
+    <service>
+        <role>KNOXIDF</role>
+        <param>
+            <name>knoxidf.knox.token.ttl</name>
+            <value>60000</value>
+        </param>
+        <param>
+            <name>knoxidf.knox.token.limit.per.user</name>
+            <value>-1</value>
+        </param>
+        <param>
+            <!-- Registration refuses anonymous callers unless this is 
explicitly true. -->
+            <name>knoxidf.client.registration.anonymous.allowed</name>
+            <value>true</value>
+        </param>
+        <param>
+            <!-- Skipping consent is a server-side deployment decision, never 
a client param. -->
+            <name>knoxidf.auto.consent.enabled</name>
+            <value>true</value>
+        </param>
+        <param>
+            <name>token.exchange.topology.name</name>
+            <value>knoxidf-token</value>
+        </param>
+    </service>
+</topology>
+```
+
+!!! warning "Anonymous client registration is opt-in"
+    `knoxidf.client.registration.anonymous.allowed` defaults to **`false`** 
(secure by
+    default). The sample above sets it to `true` only to keep the endpoint 
open for
+    experimentation. See [Security](security.md#dynamic-client-registration).
+
+### Token topology (`JWTProvider`) — `knoxidf-token.xml`
+
+```xml
+<topology>
+    <gateway>
+      <provider>
+         <role>federation</role>
+         <name>JWTProvider</name>
+         <enabled>true</enabled>
+         <param>
+            <name>knox.token.exp.server-managed</name>
+            <value>true</value>
+         </param>
+      </provider>
+      <provider>
+            <role>identity-assertion</role>
+            <name>Default</name>
+            <enabled>true</enabled>
+      </provider>
+    </gateway>
+
+    <service>
+        <role>KNOXIDF</role>
+        <param>
+           <name>knoxidf.knox.token.ttl</name>
+           <value>86400000</value>
+        </param>
+        <param>
+            <name>knoxidf.knox.token.limit.per.user</name>
+            <value>-1</value>
+        </param>
+        <param>
+            <name>knoxidf.auto.consent.enabled</name>
+            <value>true</value>
+        </param>
+    </service>
+    <service>
+        <role>KNOXTOKEN</role>
+        <param>
+            <name>knox.token.ttl</name>
+            <value>60000</value>
+        </param>
+        <param>
+            <name>knox.token.limit.per.user</name>
+            <value>-1</value>
+        </param>
+    </service>
+</topology>
+```
+
+## 4. Discover the endpoints
+
+Every subsequent step should read endpoint URLs from the discovery document 
rather than
+hard-coding paths. Fetch it from the front topology:
+
+```bash
+curl -sk 
https://knox:8443/gateway/knoxidf-ldap/knoxidf/api/v1/.well-known/openid-configuration
 | jq .
+```
+
+The response includes `issuer`, `authorization_endpoint`, `token_endpoint`,
+`userinfo_endpoint`, `jwks_uri`, `registration_endpoint`, and the supported 
grant types,
+scopes, response types, and PKCE methods. See the [Endpoint 
Reference](endpoints.md) for the
+full document.
+
+## 5. Register a client
+
+```bash
+curl -sk -X POST \
+  https://knox:8443/gateway/knoxidf-ldap/knoxidf/api/v1/client/register \
+  -H 'Content-Type: application/json' \
+  -d '{
+        "client_name": "my-first-client",
+        "redirect_uris": ["https://app.example.com/callback";],
+        "grant_types": ["authorization_code", "refresh_token"]
+      }' | jq .
+```
+
+The response contains a generated `client_id` and, for confidential clients, a
+`client_secret`. Store the secret securely — it is required to redeem 
authorization codes on
+the token endpoint (see 
[Security](security.md#token-endpoint-client-authentication)).
+
+## 6. Run a Client Credentials flow
+
+The Client Credentials grant issues a token to a confidential client with no 
interactive user
+login. Post the client credentials to the token endpoint advertised by 
discovery:
+
+```bash
+curl -sk -X POST \
+  https://knox:8443/gateway/knoxidf-ldap/knoxidf/api/v1/token \
+  -H 'Content-Type: application/x-www-form-urlencoded' \
+  -d 'grant_type=client_credentials' \
+  -d 'client_id=<client_id>' \
+  -d 'client_secret=<client_secret>' \
+  -d 'scope=openid' | jq .
+```
+
+You will receive a Knox-signed access token (and, when `openid` is requested, 
an ID token).
+Verify it against the JWKS endpoint (`jwks_uri`).
+
+## Next steps
+
+- To drive an interactive login, use the **Authorization Code + PKCE** flow — 
see the
+  [Endpoint Reference](endpoints.md#authorization-endpoint) and 
[Security](security.md#pkce).
+- To broker login to an external OIDC Provider (Keycloak, Okta, Azure AD, 
Auth0), see
+  **[Federation](federation.md)**.
+- To tune tokens, persistence, and claims, see the **[Configuration 
Reference](configuration.md)**.
diff --git a/knox-site/docs/knoxidf/index.md b/knox-site/docs/knoxidf/index.md
new file mode 100644
index 000000000..3eac8e1b5
--- /dev/null
+++ b/knox-site/docs/knoxidf/index.md
@@ -0,0 +1,92 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       https://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+# Identity Federation (OIDC Provider)
+
+## Overview
+
+Historically, Apache Knox Gateway has acted as a *federation client* — it 
delegates
+authentication to external Identity Providers (IdPs) such as CAS, SAML, OAuth 
2.0, and
+OpenID Connect (OIDC) providers (via pac4j). In that model Knox is strictly a 
relying
+party and never an identity provider itself.
+
+**KnoxIDF** turns Apache Knox into an **OAuth 2.0 / OpenID Connect Provider 
(OP)** in its
+own right, while retaining Knox's existing federation capabilities. With 
KnoxIDF:
+
+- Knox can **issue** OAuth 2.0 / OIDC tokens (access tokens and ID tokens) 
directly to clients.
+- Knox can optionally **federate** identities and tokens from external, 
well-known OIDC
+  Providers (e.g. Keycloak, Okta, Azure AD, Auth0), brokering the login and 
then re-issuing
+  its own Knox-signed tokens.
+- Downstream services integrate with Knox exactly as they would with any 
standard OIDC
+  provider — they only need to trust Knox, regardless of how authentication 
was performed
+  upstream.
+
+This makes Knox both an **OIDC Provider** and an **OIDC federation bridge**, 
enabling gradual
+migration to — or a hybrid of — Knox-centric and external identity 
architectures.
+
+![KnoxIDF architecture: a client obtains OIDC tokens from Knox; Knox can 
optionally federate authentication to external OIDC providers and issues its 
own tokens to downstream services.](../assets/images/knoxidf/architecture.png)
+
+## Why KnoxIDF
+
+Many modern architectures expect a centralized OIDC Provider that issues 
tokens to
+downstream services. Products like Okta, Azure AD, and Keycloak are commonly 
used for this,
+but introducing and operating a separate IdP is not always desirable — 
especially in
+Hadoop-centric or Knox-centric deployments where Knox is already the trusted 
edge. KnoxIDF
+closes that gap: the gateway you already run at the perimeter becomes the 
token authority for
+the services behind it.
+
+## Capabilities
+
+KnoxIDF is implemented as a new Knox service (role `KNOXIDF`) that can be 
attached to any
+topology. It provides:
+
+| Capability | Description |
+|------------|-------------|
+| Standard OIDC endpoints | Discovery (`.well-known/openid-configuration`), 
authorization, token, userinfo, JWKS, and dynamic client registration. |
+| Client Credentials flow | Machine-to-machine token issuance. |
+| Authorization Code flow + PKCE | Interactive user login with PKCE (S256) for 
public clients and `client_secret` for confidential clients. |
+| Refresh tokens | Refresh-token grant with rotation. |
+| Consent | A one-time-per-(user, client) consent screen for the Authorization 
Code flow. |
+| Federation (optional) | Broker login to one or more external OIDC Providers 
and re-issue Knox tokens. |
+| Attribute enrichment | Hard-coded ID-token claims and pluggable 
user-parameter providers (e.g. LDAP attributes). |
+| Persistence | Federated identity data persisted for traceability and 
attribute reuse (ID-token data only — no access/refresh tokens or secrets). |
+
+## How it fits into Knox
+
+KnoxIDF operates independently from pac4j-based inbound authentication and 
does not change
+existing gateway authentication flows. A topology that includes the `KNOXIDF` 
service exposes
+the OIDC endpoints; the topology's own authentication/federation providers 
(Shiro/LDAP,
+SSOCookie, JWT, etc.) still govern how the caller is authenticated before 
KnoxIDF issues a
+token. This keeps KnoxIDF modular and composable with the rest of Knox.
+
+## Where to go next
+
+- **[Getting Started](getting_started.md)** — build, deploy, register a 
client, and run your first flow.
+- **[Endpoint Reference](endpoints.md)** — every REST endpoint KnoxIDF exposes.
+- **[Configuration Reference](configuration.md)** — every configuration 
parameter.
+- **[Security](security.md)** — client authentication, PKCE, consent, 
redirect-URI validation, and secret handling.
+- **[Federation](federation.md)** — brokering login to external OIDC Providers.
+- **[Operations](operations.md)** — high availability, rate limiting, 
signing-key rotation, and auditing.
+
+!!! note "Relationship to KIP-18"
+    KnoxIDF was originally proposed and prototyped in
+    [KIP-18 — Knox as OIDC 
Provider](https://cwiki.apache.org/confluence/spaces/KNOX/pages/406618787/KIP-18+-+Knox+as+OIDC+Provider).
+    KIP-18 describes the original design and proof-of-concept. The 
implementation has since
+    evolved (for example, refresh-token support, hardened client 
authentication, and
+    automatic federated-identity persistence were added after the initial 
proposal). Where the
+    KIP and this documentation differ, **this documentation reflects the 
current code and is
+    authoritative**; KIP-18 remains useful background on the motivation and 
design.
diff --git a/knox-site/docs/knoxidf/operations.md 
b/knox-site/docs/knoxidf/operations.md
new file mode 100644
index 000000000..ddd2ab210
--- /dev/null
+++ b/knox-site/docs/knoxidf/operations.md
@@ -0,0 +1,182 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       https://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+# Operations
+
+This chapter covers running KnoxIDF in production: where identity state is 
persisted, how to
+rotate signing keys without disrupting clients, how requests are audited, and 
how KnoxIDF behaves
+behind a highly available Knox deployment.
+
+## Federated identity persistence
+
+KnoxIDF persists federated-identity data so that the same upstream user maps 
to a stable Knox
+subject across logins and restarts, and so a filtered set of profile 
attributes can be reused. It
+stores **only ID-token–derived data** — no access tokens, refresh tokens, or 
OP client secrets
+(see [Security → What is (and isn't) stored at 
rest](security.md#what-is-and-isnt-stored-at-rest)).
+
+### Backend selection
+
+The persistence backend activates automatically whenever a topology with the 
`KNOXIDF` or
+`KNOXIDF_ADMIN` role is deployed. Which backend is used follows the gateway's 
database
+configuration:
+
+| `gateway.database.type` | Backend | Notes |
+|-------------------------|---------|-------|
+| `none` (default) or `derbydb` | Self-provisioning **embedded Derby** | Uses 
the same physical embedded database as token state (under the gateway security 
directory). Zero setup. |
+| A real external type (`postgresql`, `mysql`, `oracle`, …) | **JDBC-backed** 
store | Uses the operator-configured external database. Recommended for HA. |
+
+You can also pin the implementation explicitly with the service property
+`gateway.service.KnoxIDFFederatedIdentityService.impl` (Empty / Derby / JDBC); 
an explicit value
+always wins over auto-selection. Setting it to the empty (no-op) 
implementation disables
+persistence.
+
+!!! note "Use an external database for multi-instance deployments"
+    The embedded Derby store is local to a single gateway process. For a 
clustered / HA
+    deployment where more than one Knox instance must share federated-identity 
state, configure an
+    external database (see [Configuration → 
Persistence](configuration.md#persistence-and-database)).
+
+### What is stored
+
+- **Identity mapping:** Knox subject (UUIDv5), provider name (upper-cased), 
external subject,
+  external issuer.
+- **Attributes:** the allow-listed profile claims (`preferred_username`, 
`email`, `email_verified`,
+  `given_name`, `family_name`, `name`, `locale`).
+
+The identity row and its attributes are written in a **single transaction**, 
and a unique
+constraint on `(provider, external_issuer, external_subject)` makes concurrent 
first-logins of the
+same user converge on one row.
+
+## Signing-key rotation
+
+KnoxIDF signs issued JWTs with the gateway signing key 
(`gateway.signing.key.alias`, default
+`gateway-identity`) and publishes the corresponding public key(s) on the
+[JWKS endpoint](endpoints.md#jwks-endpoint). Each published key is identified 
by a `kid` equal to
+the **SHA-256 thumbprint** of its public key, so verifiers select the right 
key by `kid` rather
+than assuming a single static key.
+
+To rotate the signing key **without breaking tokens already in the wild**:
+
+1. **Provision the new key** in the signing keystore under a new alias.
+2. **Publish both keys.** Add the *old* alias to 
`gateway.signing.key.aliases.additional` in
+   `gateway-site.xml` so the JWKS endpoint serves both the old and new public 
keys:
+
+   ```xml
+   <property>
+       <name>gateway.signing.key.aliases.additional</name>
+       <value>gateway-identity-previous</value>
+   </property>
+   ```
+
+3. **Cut over signing** by pointing `gateway.signing.key.alias` at the new 
alias. New tokens are
+   now signed with the new key; verifiers still find the old key (by its 
`kid`) on JWKS for
+   tokens signed before the cutover.
+4. **Retire the old key** once all tokens signed with it have expired: remove 
it from
+   `gateway.signing.key.aliases.additional`.
+
+Because clients resolve keys from JWKS by `kid`, no client reconfiguration is 
needed at any step.
+
+!!! tip "Order matters"
+    Publish the new key on JWKS *before* you start signing with it, and keep 
the old key published
+    *until* the last token it signed has expired. Overlapping the two windows 
is what makes the
+    rotation seamless.
+
+## Auditing
+
+KnoxIDF actions are recorded through Knox's standard audit framework, so 
KnoxIDF audit records
+appear in the same audit log as the rest of the gateway 
(`$KNOX_HOME/logs/gateway-audit.log` by
+default) and follow the gateway's configured audit layout. Security-relevant 
operations — token
+issuance, client registration, consent decisions, federated login, and 
trusted-issuer
+administration — are audited with the acting principal and outcome.
+
+Audit output is configured through the gateway's Log4j2 configuration
+(`$KNOX_HOME/conf/gateway-log4j2.xml`), the same as every other Knox audit 
stream; see
+[Audit](../config_audit.md) for audit-appender and retention configuration.
+
+## High availability
+
+KnoxIDF adds no HA mechanism of its own — it inherits Knox's standard HA 
model. Run multiple Knox
+instances behind a load balancer as you would for any other Knox service, with 
two
+KnoxIDF-specific requirements:
+
+- **Shared persistence.** All instances must point at the **same external 
database**
+  (`gateway.database.*`) so a federated identity created on one instance is 
visible on the others.
+  The embedded Derby default is per-process and is not suitable for 
multi-instance HA.
+- **Consistent signing keys.** All instances must share the same signing 
keystore and the same
+  `gateway.signing.key.alias` / `gateway.signing.key.aliases.additional` 
configuration, so a token
+  issued by one instance verifies against the JWKS served by any instance.
+
+Sticky sessions are recommended for the interactive Authorization Code / 
federation flow so that
+the browser stays on the instance holding the in-flight authorize/consent 
state, though the issued
+tokens themselves are verifiable on any instance.
+
+## Rate limiting
+
+KnoxIDF does not implement rate limiting of its own, but it does not need to — 
Knox's
+**`WebAppSec` provider** ships a rate-limiting filter you can attach to a 
KnoxIDF topology to
+throttle request flooding, whether malicious or from a misconfigured client. 
This protects the
+high-value token, authorization, and registration endpoints without any 
external infrastructure.
+
+Add the provider to the KnoxIDF topology and enable rate limiting:
+
+```xml
+<provider>
+    <role>webappsec</role>
+    <name>WebAppSec</name>
+    <enabled>true</enabled>
+    <param>
+        <name>rate.limiting.enabled</name>
+        <value>true</value>
+    </param>
+    <param>
+        <name>rate.limiting.maxRequestsPerSec</name>
+        <value>25</value>
+    </param>
+    <param>
+        <!-- -1 = reject over-limit requests; a non-negative value delays 
instead
+             and requires gateway.servlet.async.supported=true in 
gateway-site.xml -->
+        <name>rate.limiting.delayMs</name>
+        <value>-1</value>
+    </param>
+</provider>
+```
+
+The filter tracks request rate per connection (or per session when
+`rate.limiting.trackSessions=true`), delays or rejects requests over
+`rate.limiting.maxRequestsPerSec`, and can exempt trusted callers via
+`rate.limiting.ipWhitelist`. See the
+[WebAppSec provider → Rate limiting](../config_webappsec_provider.md) 
documentation for the full
+parameter set (`delayMs`, `maxWaitMs`, `throttledRequests`, `insertHeaders`, 
`ipWhitelist`, …).
+
+!!! note "Async support for non-rejecting modes"
+    A non-negative `rate.limiting.delayMs` (delay rather than reject) requires
+    `gateway.servlet.async.supported=true` in `gateway-site.xml` (it is 
`false` by default).
+
+You may still add rate limiting at the edge (load balancer / reverse proxy) as 
defense in depth.
+Anonymous client registration in particular should either be left disabled 
(the default) or, when
+enabled, fronted by the rate-limiting filter above.
+
+## Operational checklist
+
+- [ ] TLS enabled on every topology that exposes KnoxIDF endpoints.
+- [ ] External database configured for any multi-instance / HA deployment.
+- [ ] Signing keystore and `gateway.signing.key.alias*` identical across all 
instances.
+- [ ] `knoxidf.client.registration.anonymous.allowed` reviewed (default 
`false`).
+- [ ] `knoxidf.auto.consent.enabled` reviewed (default `false`).
+- [ ] Federated OP client secrets stored as aliases, not plaintext.
+- [ ] Trusted-issuer registry (`KNOXIDF_ADMIN`) exposed only on an 
administrator-restricted topology.
+- [ ] Rate limiting enabled (WebAppSec provider on the topology, and/or at the 
edge) for the token / authorize / registration endpoints.
+- [ ] Audit log retention configured.
diff --git a/knox-site/docs/knoxidf/security.md 
b/knox-site/docs/knoxidf/security.md
new file mode 100644
index 000000000..47ded7046
--- /dev/null
+++ b/knox-site/docs/knoxidf/security.md
@@ -0,0 +1,183 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       https://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+# Security
+
+This chapter describes the security controls KnoxIDF enforces as an OAuth 2.0 
/ OIDC provider.
+Understanding them is important when hardening a deployment and when reasoning 
about the trust
+boundary between clients, Knox, and any external OIDC Providers.
+
+!!! warning "Always run over TLS"
+    OAuth 2.0 and OIDC assume a confidential channel. Every token-bearing 
endpoint must be
+    served over HTTPS in production. The `ssl.enabled=false` option is for 
local development
+    only.
+
+## Token-endpoint client authentication
+
+The token endpoint independently authenticates the client when redeeming an 
authorization code —
+it does not rely on the upstream `JWTProvider` (which authenticates the 
*request* but does not
+verify the OAuth `client_secret`). The check is chosen by what was stored at 
authorize time:
+
+- **PKCE path** — if the authorization request included a `code_challenge`, 
the client must
+  present a matching `code_verifier`. See [PKCE](#pkce).
+- **Client-secret path** — if no `code_challenge` was stored, the client must 
present a valid
+  `client_secret`.
+
+The two paths are mutually exclusive, and there is no path where neither 
applies. The
+`refresh_token` grant always requires a `client_secret` (there is no PKCE 
bypass for refresh).
+
+Client-secret verification is **constant-time**. The secret on the wire 
encodes the token id and
+a passcode; Knox recomputes an HMAC (keyed by the `knox.token.hash.key` alias, 
over the token id,
+issue time, and user name as a per-token salt) and compares it to the stored 
value with a
+constant-time comparison. The embedded token id must equal the request 
`client_id`, binding the
+secret to the specific client.
+
+## PKCE
+
+Only the **S256** code-challenge method is accepted. `plain` (and an omitted 
method, which OAuth
+would otherwise default to `plain`) is **rejected** — both at the 
authorization endpoint (which
+refuses to store a non-S256 challenge) and at the token endpoint (which 
refuses to verify with
+any other method). This is enforced as defense in depth at both ends of the 
flow. The S256
+challenge is computed as `BASE64URL(SHA-256(ASCII(code_verifier)))` without 
padding, per
+RFC 7636.
+
+Public clients (no `client_secret`) must use PKCE; this is how a public client 
proves possession
+of the authorization code at redemption time.
+
+## Single-use authorization codes
+
+Authorization codes are single-use. The code is **atomically consumed before 
any token is
+issued**, so of any number of concurrent redemptions of the same code, exactly 
one succeeds and
+the rest receive `invalid_grant`. This closes the check-then-issue replay 
window.
+
+A code that fails *validation* (bad `redirect_uri`, wrong `client_id`, 
PKCE/secret failure) is
+deliberately **not** consumed — this prevents a denial-of-service in which an 
attacker replays a
+victim's code with bad parameters to burn it before the legitimate client 
redeems it.
+
+## Redirect-URI validation
+
+Open redirects are prevented both at registration and at authorization time.
+
+**At registration** (`/client/register`):
+
+- The **host** component may not contain a wildcard.
+- **HTTPS is required.** Plain `http://` is accepted only for loopback hosts 
(`localhost`,
+  `127.0.0.1`, `::1`), per RFC 8252 for native apps.
+- A wildcard `*` is permitted only at the **end of the path**, never in the 
host, query, or
+  fragment.
+
+**At authorization** (`/authorize`):
+
+- Non-wildcard URIs are matched by exact string equality.
+- Wildcard URIs are matched by first comparing the **origin** (scheme + host + 
port) so that a
+  registered `https://good.example*` cannot match 
`https://good.example.evil.com`. Only then is
+  the path prefix compared, after both paths are `URI.normalize()`d — 
collapsing traversal
+  segments (e.g. `/callback/../admin`) so a raw prefix match cannot be tricked 
into escaping the
+  registered prefix.
+
+## Consent
+
+For the Authorization Code flow, KnoxIDF presents a [consent 
page](endpoints.md#consent-page)
+where the user approves the scopes a client is requesting. Consent is 
**one-time per (user,
+client, scopes)**: once granted, subsequent authorization requests for the 
same scopes proceed
+without re-prompting.
+
+Whether consent can be skipped is a **server-side deployment decision**, 
governed by the
+topology parameter `knoxidf.auto.consent.enabled`. It is read from the 
topology configuration at
+startup and is **never** read from the incoming HTTP request — a client cannot 
bypass the consent
+screen by sending an `auto_consent=true` parameter.
+
+Consent records are stored as metadata on the client's token record, under a 
fixed-width key
+derived as `"consent_"` + the first 20 hex characters of `SHA-256(subject)` 
(28 characters
+total). Hashing the subject keeps the key within the storage column width 
regardless of how long
+the username or federated UUID subject is, and the read and write paths derive 
the key
+identically so they always agree.
+
+## Dynamic client registration
+
+Dynamic client registration is a deliberately supported deployment mode, but 
it is **not open by
+default**. The endpoint refuses anonymous callers unless the topology 
explicitly sets:
+
+```xml
+<param>
+    <name>knoxidf.client.registration.anonymous.allowed</name>
+    <value>true</value>
+</param>
+```
+
+The default is **`false`** (secure by default). When open registration is 
enabled, the
+token-endpoint client authentication described above is what still prevents a
+registered-but-unauthenticated client from redeeming another client's 
authorization code.
+
+## Federated id_token validation
+
+When Knox brokers login to an external OIDC Provider, the OP's `id_token` is 
**fully validated
+before any claim is trusted** — it is never decoded and trusted as-is. 
Validation fails closed at
+each stage:
+
+1. **Signature + `exp`/`nbf`** — verified against the OP's JWKS (fetched from 
the configured
+   `jwks.endpoint`) using the configured signature algorithm (default `RS256`).
+2. **Issuer** — must equal the statically configured 
`federated.op.<name>.issuer`, not a value
+   read from the token itself.
+3. **Audience** — must contain the configured `federated.op.<name>.clientId` 
(Knox's client id
+   at the OP).
+4. **Subject** — `sub` must be present and non-blank.
+5. **Nonce** — the token's `nonce` must equal the nonce Knox generated for 
that login session,
+   binding the token to the specific authorization request.
+
+If the OP configuration is missing its `jwks.endpoint`, `issuer`, or 
`clientId`, validation is
+refused outright — no OP token can be accepted.
+
+See [Federation](federation.md) for the full broker flow.
+
+## Trusted issuer registry
+
+The set of external issuers Knox will accept `id_token`s from is administered 
through the
+[Trusted OIDC Issuers admin API](endpoints.md#trusted-oidc-issuers-admin) 
(`KNOXIDF_ADMIN`
+role), which should be exposed only on an administrator-restricted topology. 
Registered issuer
+URLs must be HTTPS, and there is a configurable upper bound on the number of 
trusted issuers.
+
+## Secret handling
+
+- **Federated OP client secrets** can be resolved from Knox's `AliasService` 
rather than being
+  written in plaintext in the topology. Set 
`federated.op.<name>.clientSecret.alias` to an alias
+  name; it takes precedence over the plaintext `clientSecret` parameter. If an 
alias is
+  configured but cannot be resolved, resolution **fails closed** — the request 
to the OP is not
+  made, rather than silently falling back to a plaintext value.
+- **Federated access tokens are never persisted.** Only the federated 
*identity* (ID-token–derived
+  data) is stored; the OP's access token is discarded immediately after the 
token exchange.
+  Persisting an OP bearer token in plaintext token metadata would be a 
secret-at-rest exposure.
+
+## Subject derivation
+
+For federated users, the Knox `sub` is a deterministic **UUIDv5** over a fixed 
namespace UUID
+(`6ba7b811-9dad-11d1-80b4-00c04fd430c8`, the RFC 4122 "URL" namespace) with 
the name
+`issuer + "|" + subject`. The same upstream user therefore always maps to the 
same Knox subject
+across logins and gateway restarts.
+
+!!! danger "Do not change the subject namespace"
+    Because the `sub` is derived from a fixed namespace UUID, changing that 
namespace would
+    rewrite the subject of **every** previously persisted federated user. The 
namespace is an
+    immutable part of the deployment's identity contract.
+
+## What is (and isn't) stored at rest
+
+KnoxIDF persists **only ID-token–derived federated identity data** — the core 
identity mapping
+(Knox subject, provider, external subject, external issuer) and a filtered set 
of profile
+attributes (`preferred_username`, `email`, `email_verified`, `given_name`, 
`family_name`,
+`name`, `locale`). It does **not** store access tokens, refresh tokens, or OP 
client secrets.
+This keeps the persisted footprint to what is needed for traceability and 
attribute reuse.
diff --git a/knox-site/mkdocs.yml b/knox-site/mkdocs.yml
index f147f0937..c0f91bdbb 100644
--- a/knox-site/mkdocs.yml
+++ b/knox-site/mkdocs.yml
@@ -114,6 +114,14 @@ nav:
           - General Troubleshooting: admin_troubleshooting.md
           - Authentication Issues: auth_troubleshooting.md
           - Service-Specific Issues: service_troubleshooting.md
+  - Identity Federation (OIDC Provider):
+      - Overview: knoxidf/index.md
+      - Getting Started: knoxidf/getting_started.md
+      - Endpoint Reference: knoxidf/endpoints.md
+      - Configuration Reference: knoxidf/configuration.md
+      - Security: knoxidf/security.md
+      - Federation: knoxidf/federation.md
+      - Operations: knoxidf/operations.md
   - Developer Guide:
       - Overview: dev-guide/book.md
       - Extending Knox:
@@ -134,7 +142,11 @@ markdown_extensions:
       permalink: true
   - admonition
   - pymdownx.details
-  - pymdownx.superfences
+  - pymdownx.superfences:
+      custom_fences:
+        - name: mermaid
+          class: mermaid
+          format: !!python/name:pymdownx.superfences.fence_code_format
   - pymdownx.highlight:
       anchor_linenums: true
   - pymdownx.inlinehilite

Reply via email to