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)
| Filter | Class | Role |
|---|---|---|
auth_token | AuthProtocol (keystonemiddleware/auth_token/__init__.py:591-892) | validates X-Auth-Token (and X-Service-Token) against Keystone |
oauth2_token | OAuth2Protocol (keystonemiddleware/oauth2_token.py:29) | same, with Authorization: Bearer <token> |
oauth2_mtls_token | OAuth2mTlsProtocol (keystonemiddleware/oauth2_mtls_token.py:28) | Bearer + check that the client certificate's thumbprint matches oauth2_credential.x5t#S256 of the token |
external_oauth2_token | keystonemiddleware/external_oauth2_token.py | validation 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…) |
audit | AuditMiddleware (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)
- Remove every identity header sent by the client (
remove_auth_headers,keystonemiddleware/auth_token/_request.py:206-227). - 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(defaultservice), whenservice_token_roles_requiredis true; - a valid service token allows an expired user token (
allow_expired).
- it is valid as a service token if it carries one of the roles of
- Validate **
X-Auth-Token** (orX-Storage-Token). The steps:- read the cache, otherwise call Keystone;
- check the expiry (unless
allow_expired); - check the access rules of the application credential, if any (
validate_allowed_request,keystonemiddleware/auth_token/__init__.py:543-590); - check the bind (Kerberos), according to
enforce_token_bind.
- 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 fromX-Identity-Status.
- if the user token is not valid, or a service token is present but invalid, the request is rejected with 401 and
- Headers injected for the service (
keystonemiddleware/auth_token/_request.py:79-201):
| Header | Value |
|---|---|
X-Identity-Status / X-Service-Identity-Status | Confirmed or Invalid |
X-User-Id, X-User-Name, X-User-Domain-Id, X-User-Domain-Name | the user |
X-Project-Id, X-Project-Name, X-Project-Domain-Id, X-Project-Domain-Name | the project scope |
X-Domain-Id, X-Domain-Name | the domain scope |
X-Roles | the roles, comma-separated, after expansion of implied roles by Keystone (member brings reader) |
X-Is-Admin-Project | True/False |
OpenStack-System-Scope | all for a system-scoped token |
X-Service-Catalog | the 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-Tenant | deprecated 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).
- 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)
| Option | Default | Effect |
|---|---|---|
www_authenticate_uri | — | URI announced in WWW-Authenticate |
delay_auth_decision | false | let invalid requests through (marked Invalid) |
http_connect_timeout, http_request_max_retries | —, 3 | calls to Keystone |
memcached_servers | — | shared token cache; without it, the cache is per process |
token_cache_time | 300 | lifetime of a validation in the cache, so the maximum delay before a revocation is honoured |
memcache_security_strategy, memcache_secret_key | None | MAC or ENCRYPT for the cached entries |
include_service_catalog | true | X-Service-Catalog header |
service_token_roles, service_token_roles_required | service, true | definition of a valid service token |
enforce_token_bind | permissive | Kerberos 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.