Skip to content

OAuth 2.0 Protected Resource Metadata endpoint#260773

Open
elena-shostak wants to merge 10 commits intoelastic:mainfrom
elena-shostak:2750-resource-endpoint
Open

OAuth 2.0 Protected Resource Metadata endpoint#260773
elena-shostak wants to merge 10 commits intoelastic:mainfrom
elena-shostak:2750-resource-endpoint

Conversation

@elena-shostak
Copy link
Copy Markdown
Contributor

@elena-shostak elena-shostak commented Apr 1, 2026

Summary

OAuth 2.0 Protected Resource Metadata endpoint https://datatracker.ietf.org/doc/rfc9728/

xpack.security.mcp.oauth2.metadata:
  authorization_servers:
    - <server1>
    - <server2>
  resource: <resource_uri>
  bearer_methods_supported:
    - header
    - body
    - query
  scopes_supported:
    - all
  resource_documentation: <resource_documentation_uri>

How to test

  1. Add configuration to Kibana
xpack.security.mcp.oauth2.metadata:
  authorization_servers: ['https://localhost:8444/oauth2']
  resource: http://localhost:5601

Note

You may need to add self signed certificate to claude/settings.json
"NODE_EXTRA_CA_CERTS": "<path_to_kibana>/src/platform/packages/shared/kbn-dev-utils/certs/ca.crt"

  1. Start ES and Kibana with UIAM
UIAM_OAUTH=true yarn es serverless --projectType observability --uiam
yarn start --serverless=oblt --uiam
  1. Login to Kibana
  2. Register Claude as a client
curl --location 'https://localhost:8443/uiam/api/v1/oauth/clients' \
--header 'Content-Type: application/json' \
--header 'Authorization: ApiKey essu_dev_TnpKcmMyVTFkMEo2WW5scU5XUm9PVWw2TVRNNmJqSXRVbWxTVEZNeVowNVRkMWhUVWpCd1l6SjBadz09AAAAAN10T0s=' \
--data '{
    "client_name": "Claude Code",
    "resource": "http://localhost:5601/"
}'

You should get a clientId with response

{
    "id": "<your_client_id>"
    "type": "public",
    "resource": "http://localhost:5601/",
    "creation": "2026-04-01T14:56:04.184718009Z",
    "revoked": false,
    "connections": {
        "active": [],
        "revoked": []
    },
    "client_name": "Claude Code",
    "client_metadata": {}
}
  1. Add Kibana MCP to Claude
claude mcp add --transport http --client-id <your_client_id> kibana-mcp http://localhost:5601/api/agent_builder/mcp
  1. Check the connection
claud mcp list

Should output

kibana-mcp: http://localhost:5601/api/agent_builder/mcp (HTTP) - !Needs authentication
  1. Initiate Claude session and use /mcp to start OAuth flow
Screenshot 2026-04-08 at 12 02 12
Screen.Recording.2026-04-08.at.13.23.44.mov

Checklist

Closes: https://github.com/elastic/kibana-team/issues/2750
Relates: #256182

@elena-shostak elena-shostak force-pushed the 2750-resource-endpoint branch from a031945 to ff74af2 Compare April 8, 2026 10:25
Comment on lines +280 to +282
const expectedAudience = this.#kibanaServerURL.endsWith('/')
? this.#kibanaServerURL
: `${this.#kibanaServerURL}/`;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Claude's client normalizes the URL to the canonical form with an explicit path. UIAM should treat these as equivalent when comparing, but it doesn't right now, so appending trailing slash as temporary fix, otherwise we would get

Audience mismatch: expected http://localhost:5601 but token has http://localhost:5601/

@elena-shostak elena-shostak added release_note:skip Skip the PR/issue when compiling release notes backport:skip This PR does not require backporting Team:Security Platform Security: Auth, Users, Roles, Spaces, Audit Logging, etc t// Feature:Security/Authorization Platform Security - Authorization Feature:Security/Authentication Platform Security - Authentication and removed Feature:Security/Authorization Platform Security - Authorization labels Apr 8, 2026
@elasticmachine
Copy link
Copy Markdown
Contributor

elasticmachine commented Apr 8, 2026

⏳ Build in-progress, with failures

Failed CI Steps

Test Failures

  • [job] [logs] Jest Tests #1 / #initializeUiamContainers should be able to initialize UIAM containers if Cosmos DB database and collections exist
  • [job] [logs] Jest Tests #1 / #initializeUiamContainers should be able to initialize UIAM containers if Cosmos DB database and collections exist
  • [job] [logs] Jest Tests #1 / #initializeUiamContainers should be able to initialize UIAM containers if Cosmos DB database does not exist
  • [job] [logs] Jest Tests #1 / #initializeUiamContainers should be able to initialize UIAM containers if Cosmos DB database does not exist
  • [job] [logs] Jest Tests #1 / #runUiamContainer() should be able to run UIAM containers
  • [job] [logs] Jest Tests #1 / #runUiamContainer() should be able to run UIAM containers
  • [job] [logs] Jest Tests #9 / GET /.well-known/oauth-protected-resource when mcp config is set returns 404 for path-aware discovery requests
  • [job] [logs] Jest Tests #9 / GET /.well-known/oauth-protected-resource when mcp config is set returns 404 for path-aware discovery requests
  • [job] [logs] affected Scout: [ observability / slo ] plugin / local-serverless-observability_complete - SLOs Overview - Go to slos overview and validate data retention tab
  • [job] [logs] affected Scout: [ platform / security ] plugin / local-serverless-security_complete - [NON-MKI] UIAM OAuth token exchange on MCP endpoint - should exchange OAuth token and authenticate successfully on MCP endpoint
  • [job] [logs] affected Scout: [ platform / security ] plugin / local-serverless-security_complete - [NON-MKI] UIAM OAuth token exchange on MCP endpoint - should exchange OAuth token and authenticate successfully on MCP endpoint
  • [job] [logs] Jest Tests #1 / runServerlessCluster() should start 3 serverless ES nodes and three UIAM containers when UIAM_OAUTH is enabled
  • [job] [logs] Jest Tests #1 / runServerlessCluster() should start 3 serverless ES nodes and three UIAM containers when UIAM_OAUTH is enabled
  • [job] [logs] Jest Tests #2 / user_details_left useTabs can show only Resolution tab when no other tabs apply
  • [job] [logs] Jest Tests #2 / user_details_left useTabs can show only Resolution tab when no other tabs apply

History

@elena-shostak elena-shostak requested a review from azasypkin April 8, 2026 15:37
@elena-shostak elena-shostak marked this pull request as ready for review April 8, 2026 15:37
@elena-shostak elena-shostak requested review from a team as code owners April 8, 2026 15:37
@elasticmachine
Copy link
Copy Markdown
Contributor

Pinging @elastic/kibana-security (Team:Security)

* Override with `MOCK_IDP_KIBANA_URL`.
*/
async function extraDockerParamsForUiamOauthContainer(): Promise<string[]> {
const kibanaUrl = process.env.MOCK_IDP_KIBANA_URL ?? 'http://localhost:5601';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we'll want to pass in kibanaUrl from src/platform/packages/shared/kbn-es/src/utils/docker.ts instead of hard coding the URL.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting Feature:Security/Authentication Platform Security - Authentication release_note:skip Skip the PR/issue when compiling release notes Team:Security Platform Security: Auth, Users, Roles, Spaces, Audit Logging, etc t//

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants