OpenKeel: the sovereign French Cloud solution of the inherent group, with a European reach Discover inherent

Reverse-spec · Libraries

keystonemiddleware — Middleware interface

Middleware interface — keystonemiddleware — branch stable/2026.2

Branch stable/2026.2 @ 3a8a835bb573 (13.0.1 + 2 maintenance commits) — repository https://opendev.org/openstack/keystonemiddleware — analysed on 2026-10-28

keystonemiddleware exposes no API. It provides WSGI middlewares that every OpenStack service puts in front of its API, through paste or in code:

  • auth_token checks the token of every incoming request against Keystone, and passes the identity to the service as **X-* headers**;
  • audit publishes a CADF event for every request.

Its contract has two sides:

  • what it requires from Keystone (interactions);
  • what it guarantees to the protected service: headers and statuses, described below.

1. Filters (setup.cfg:39-44, paste.filter_factory)

FilterClassRole
auth_tokenAuthProtocol (keystonemiddleware/auth_token/__init__.py:591-892)validates X-Auth-Token (and X-Service-Token) against Keystone
oauth2_tokenOAuth2Protocol (keystonemiddleware/oauth2_token.py:29)same, with Authorization: Bearer <token>
oauth2_mtls_tokenOAuth2mTlsProtocol (keystonemiddleware/oauth2_mtls_token.py:28)Bearer + check that the client certificate's thumbprint matches oauth2_credential.x5t#S256 of the token
external_oauth2_tokenkeystonemiddleware/external_oauth2_token.pyvalidation by introspection at an external OAuth2 server (client_secret_basic, client_secret_post, tls_client_auth, private_key_jwt…), then mapping of the claims to identity headers (mapping_user_id, mapping_roles…)
auditAuditMiddleware (keystonemiddleware/audit/__init__.py:82-172)CADF audit.http.request / audit.http.response events

2. auth_token: request flow (keystonemiddleware/auth_token/__init__.py:343-470, keystonemiddleware/auth_token/__init__.py:648-722)

  1. Remove every identity header sent by the client (remove_auth_headers, keystonemiddleware/auth_token/_request.py:206-227).
  2. If **X-Service-Token** is present, validate it:
    • it is valid as a service token if it carries one of the roles of service_token_roles (default service), when service_token_roles_required is true;
    • a valid service token allows an expired user token (allow_expired).
  3. Validate **X-Auth-Token** (or X-Storage-Token). The steps:
    1. read the cache, otherwise call Keystone;
    2. check the expiry (unless allow_expired);
    3. check the access rules of the application credential, if any (validate_allowed_request, keystonemiddleware/auth_token/__init__.py:543-590);
    4. check the bind (Kerberos), according to enforce_token_bind.
  4. Decision:
    • if the user token is not valid, or a service token is present but invalid, the request is rejected with 401 and WWW-Authenticate: Keystone uri="<www_authenticate_uri>", with the body {"error": {"code": 401, "title": "Unauthorized", "message": "The request you have made requires authentication."}};
    • with **delay_auth_decision = true, the request **goes through and the service decides from X-Identity-Status.
  5. Headers injected for the service (keystonemiddleware/auth_token/_request.py:79-201):
HeaderValue
X-Identity-Status / X-Service-Identity-StatusConfirmed or Invalid
X-User-Id, X-User-Name, X-User-Domain-Id, X-User-Domain-Namethe user
X-Project-Id, X-Project-Name, X-Project-Domain-Id, X-Project-Domain-Namethe project scope
X-Domain-Id, X-Domain-Namethe domain scope
X-Rolesthe roles, comma-separated, after expansion of implied roles by Keystone (member brings reader)
X-Is-Admin-ProjectTrue/False
OpenStack-System-Scopeall for a system-scoped token
X-Service-Catalogthe catalog as JSON (if include_service_catalog)
X-Service-*the same fields for the service token (X-Service-Roles…)
X-Role, X-User, X-Tenant-Id, X-Tenant-Name, X-Tenantdeprecated copies

The environment also receives keystone.token_info (the raw token) and keystone.token_auth (an auth plugin the service can reuse to call other services on behalf of the user).

  1. Response: any 401 from the service also receives WWW-Authenticate (keystonemiddleware/auth_token/__init__.py:710-725).

Access rules (application credentials): a rule matches when service equals [keystone_authtoken]/service_type and method and path match. In path, * stands for one segment, ** for any suffix and {x} for one segment (keystonemiddleware/auth_token/__init__.py:280-297). Without service_type, or when the type is not in the token's catalog, the token is refused.

3. Configuration ([keystone_authtoken], keystonemiddleware/auth_token/_opts.py)

OptionDefaultEffect
www_authenticate_uri—URI announced in WWW-Authenticate
delay_auth_decisionfalselet invalid requests through (marked Invalid)
http_connect_timeout, http_request_max_retries—, 3calls to Keystone
memcached_servers—shared token cache; without it, the cache is per process
token_cache_time300lifetime of a validation in the cache, so the maximum delay before a revocation is honoured
memcache_security_strategy, memcache_secret_keyNoneMAC or ENCRYPT for the cached entries
include_service_catalogtrueX-Service-Catalog header
service_token_roles, service_token_roles_requiredservice, truedefinition of a valid service token
enforce_token_bindpermissiveKerberos bind
service_type—required for application credential access rules
auth_type + plugin options—the middleware's own credentials towards Keystone (keystoneauth)

Source: reverse-spec-keystonemiddleware/01-middleware-interface_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.