Summary
Test the metadata.http.oauth2 field in AuthPolicy, which enables Authorino to authenticate with external HTTP metadata services using the OAuth2 Client Credentials Grant (RFC 6749).
Docs: https://docs.kuadrant.io/1.4.x/authorino/docs/features/#http-getget-by-post-metadatahttp
Originating PR: Kuadrant/authorino#379 (carried forward to v1beta3 via Kuadrant/authorino#417)
Context
When Authorino fetches external metadata via metadata.http, it can authenticate itself to the metadata server in two ways:
- Shared secret (
sharedSecretRef) — a static secret passed in the request
- OAuth2 Client Credentials (
oauth2) — Authorino obtains an access token from a token endpoint and uses it to authenticate
The oauth2 option is currently untested in the testsuite. The MetadataSection.add_http() method in sections.py supports shared_secret_ref but does not yet support oauth2.
Important distinction: This is NOT about identity.oauth2Introspection (which validates incoming user tokens). This feature authenticates Authorino itself when calling external HTTP metadata endpoints.
CRD Spec (metadata.http.oauth2)
From the AuthPolicy/AuthConfig CRD on cluster:
| Field |
Type |
Required |
Description |
tokenUrl |
string |
Yes |
Token endpoint URL of the OAuth2 resource server |
clientId |
string |
Yes |
OAuth2 Client ID |
clientSecretRef |
{name, key} |
Yes |
Reference to a K8s Secret key storing the OAuth2 Client Secret |
scopes |
[]string |
No |
Optional scopes for the client credentials grant |
extraParams |
map[string]string |
No |
Optional extra parameters for token requests |
cache |
bool |
No |
Cache and reuse the token until expired (default: true). Set to false to force-fetch on every request |
When oauth2 and sharedSecretRef are both set, sharedSecretRef is ignored.
The credentials field on metadata.http controls where the obtained access token is placed in the request to the metadata service (defaults to Authorization: Bearer <token>).
Suggested Code Changes
1. Add OAuth2ClientCredentials dataclass
In testsuite/kuadrant/policy/authorization/__init__.py, add a dataclass following the pattern of existing types like Credentials and Cache:
@dataclass
class OAuth2ClientCredentials:
"""OAuth2 Client Credentials Grant configuration for HTTP metadata authentication."""
tokenUrl: str
clientId: str
clientSecretRef: dict[str, str]
scopes: list[str] = None
extraParams: dict[str, str] = None
cache: bool = True
2. Add oauth2 parameter to MetadataSection.add_http()
In testsuite/kuadrant/policy/authorization/sections.py, extend add_http() to accept the new dataclass:
@modify
def add_http(
self,
name,
endpoint,
method: Literal["GET", "POST"],
credentials: Credentials = None,
shared_secret_ref: dict[str, str] = None,
oauth2: OAuth2ClientCredentials = None,
**common_features,
):
"""Set metadata http external auth feature"""
http_config: dict = {
"url": endpoint,
"method": method,
"headers": {"Accept": {"value": "application/json"}},
}
if credentials:
http_config["credentials"] = asdict(credentials)
if shared_secret_ref:
http_config["sharedSecretRef"] = shared_secret_ref
if oauth2:
http_config["oauth2"] = asdict(oauth2)
self.add_item(name, {"http": http_config}, **common_features)
3. New test module
Create testsuite/tests/singlecluster/authorino/metadata/test_http_oauth2.py.
Tests should use Keycloak as the OAuth2 token server and Mockserver as the metadata endpoint.
Test setup pattern (following existing metadata tests):
# conftest.py already provides create_client_secret for building K8s Secrets
# with clientID/clientSecret keys (used by Authorino for OAuth2 auth)
@pytest.fixture(scope="module")
def client_secret(create_client_secret, keycloak, blame):
"""Create K8s Secret with Keycloak client credentials for OAuth2"""
return create_client_secret(blame("oauth2-secret"), keycloak.client.auth_id, keycloak.client.secret)
@pytest.fixture(scope="module")
def mock_metadata_endpoint(request, mockserver, module_label):
"""Mockserver expectation simulating an OAuth2-protected metadata endpoint"""
request.addfinalizer(lambda: mockserver.clear_expectation(module_label))
return mockserver.create_response_expectation(
module_label, {"key": "value"}, ContentType.APPLICATION_JSON
)
@pytest.fixture(scope="module")
def authorization(authorization, mock_metadata_endpoint, client_secret, keycloak, module_label):
"""Add HTTP metadata with OAuth2 client credentials authentication"""
authorization.metadata.add_http(
"oauth2-metadata",
mock_metadata_endpoint,
"GET",
oauth2=OAuth2ClientCredentials(
tokenUrl=keycloak.well_known["token_endpoint"],
clientId=keycloak.client.auth_id,
clientSecretRef={"name": client_secret.name(), "key": "clientSecret"},
),
)
# Add OPA/response to verify metadata was fetched
authorization.responses.add_simple("auth.metadata.oauth2-metadata")
return authorization
Suggested Test Cases
Core Functionality
-
Basic OAuth2 metadata fetch (GET)
Verify that Authorino successfully obtains an access token via client credentials grant and uses it to fetch metadata from an OAuth2-protected HTTP endpoint using GET method. Assert 200 and metadata present in response.
-
OAuth2 metadata fetch (POST)
Same as above but with method: POST.
-
OAuth2 with scopes
Configure scopes: ["email", "profile"] and verify the token request includes them. Use Mockserver or Keycloak to validate scopes are passed.
-
OAuth2 with extraParams
Configure extraParams: {"audience": "my-api"} and verify the extra parameters are sent to the token endpoint.
Token Caching
-
Token caching enabled (default)
With cache: true (or omitted — the default), send multiple requests and verify that Authorino reuses the access token across requests rather than requesting a new one for each authorization.
-
Token caching disabled
Set cache: false and verify Authorino fetches a new access token for every authorization request.
Edge Cases
- Invalid client credentials
Configure oauth2 with wrong clientId or clientSecretRef pointing to a non-existent Secret. Verify the request is denied (expected 403 — metadata fetch failure should result in authorization failure).
Summary
Test the
metadata.http.oauth2field in AuthPolicy, which enables Authorino to authenticate with external HTTP metadata services using the OAuth2 Client Credentials Grant (RFC 6749).Docs: https://docs.kuadrant.io/1.4.x/authorino/docs/features/#http-getget-by-post-metadatahttp
Originating PR: Kuadrant/authorino#379 (carried forward to v1beta3 via Kuadrant/authorino#417)
Context
When Authorino fetches external metadata via
metadata.http, it can authenticate itself to the metadata server in two ways:sharedSecretRef) — a static secret passed in the requestoauth2) — Authorino obtains an access token from a token endpoint and uses it to authenticateThe
oauth2option is currently untested in the testsuite. TheMetadataSection.add_http()method insections.pysupportsshared_secret_refbut does not yet supportoauth2.CRD Spec (
metadata.http.oauth2)From the AuthPolicy/AuthConfig CRD on cluster:
tokenUrlstringclientIdstringclientSecretRef{name, key}scopes[]stringextraParamsmap[string]stringcachebooltrue). Set tofalseto force-fetch on every requestWhen
oauth2andsharedSecretRefare both set,sharedSecretRefis ignored.The
credentialsfield onmetadata.httpcontrols where the obtained access token is placed in the request to the metadata service (defaults toAuthorization: Bearer <token>).Suggested Code Changes
1. Add
OAuth2ClientCredentialsdataclassIn
testsuite/kuadrant/policy/authorization/__init__.py, add a dataclass following the pattern of existing types likeCredentialsandCache:2. Add
oauth2parameter toMetadataSection.add_http()In
testsuite/kuadrant/policy/authorization/sections.py, extendadd_http()to accept the new dataclass:3. New test module
Create
testsuite/tests/singlecluster/authorino/metadata/test_http_oauth2.py.Tests should use Keycloak as the OAuth2 token server and Mockserver as the metadata endpoint.
Test setup pattern (following existing metadata tests):
Suggested Test Cases
Core Functionality
Basic OAuth2 metadata fetch (GET)
Verify that Authorino successfully obtains an access token via client credentials grant and uses it to fetch metadata from an OAuth2-protected HTTP endpoint using GET method. Assert 200 and metadata present in response.
OAuth2 metadata fetch (POST)
Same as above but with
method: POST.OAuth2 with scopes
Configure
scopes: ["email", "profile"]and verify the token request includes them. Use Mockserver or Keycloak to validate scopes are passed.OAuth2 with extraParams
Configure
extraParams: {"audience": "my-api"}and verify the extra parameters are sent to the token endpoint.Token Caching
Token caching enabled (default)
With
cache: true(or omitted — the default), send multiple requests and verify that Authorino reuses the access token across requests rather than requesting a new one for each authorization.Token caching disabled
Set
cache: falseand verify Authorino fetches a new access token for every authorization request.Edge Cases
Configure
oauth2with wrongclientIdorclientSecretRefpointing to a non-existent Secret. Verify the request is denied (expected 403 — metadata fetch failure should result in authorization failure).