[Connectors v2] OAuth 2.0 Authorization Code Grant#252369
Conversation
## Summary Closes elastic/search-team#12248 ~WIP. Don't review yet.~ This branch implements ~a _rough_, proof-of-concept,~ Authorization Code Grant Flow for the (yet unmerged) Sharepoint Online v2 connector, as well as for the merged (modified here) Notion v2 connector. The goal is to use this as a concrete example to frame discussion around, and it iterate off of.  **Initial implementation:** @seanstory: This has been entirely generated by code assistants, so thorough review will eventually be needed, _especially_ because this is an implementation of a hairy security protocol. Also, this implementation is missing a LOT of necessary bits. Some of which are: 1. cleanup of stale state with taskmanager task ✅ 2. get refresh tokens working ✅ 3. unit tests 🟡 4. check on rate limiting of these endpoints? Potential resource exhaustion ✅ 5. prompt for `tenant-id`, instead of auth URL and token URL? 6. redirect to actual page, not HTML template ✅ 1. PM feedback first 7. telemetry 8. documentation 🟡 **Additional changes:** @lorenabalan: #246655 (comment) ### What's in the box? 1. New Auth Type (oauth_authorization_code.ts) - Zod schema defining OAuth configuration (authorizationUrl, tokenUrl, clientId, clientSecret, scope) - configure() method that retrieves and refreshes tokens via ctx.getToken() - Integration with existing connector auth framework 2. OAuth State Management (oauth_state_client.ts) - PKCE state/verifier generation using crypto.randomBytes - State storage in new oauth_state saved object type - 10-minute expiration with cleanup capability - Encrypted storage of code_verifier 3. Token Management (extended connector_token_client.ts) - New methods: createWithRefreshToken(), updateWithRefreshToken(), getRefreshToken() - Encrypted storage of access_token and refresh_token - Tracks expiration for both tokens 4. HTTP Routes - POST /api/actions/connector/{id}/_oauth_authorize - Initiates OAuth flow, returns authorization URL - GET /api/actions/connector/_oauth_callback - Handles OAuth callback, exchanges code for tokens 5. Token Retrieval (get_oauth_authorization_code_access_token.ts) - Fetches stored access token - Auto-refreshes expired tokens using refresh token - Returns null if authorization needed 6. OAuth Token Requests - request_oauth_authorization_code_token.ts - Exchanges authorization code for tokens - request_oauth_refresh_token.ts - Refreshes access token 7. Integration Points - Updated ActionsClient.getOAuthAccessToken() to support "authorization_code" type - Modified getAxiosInstanceWithAuth() to call getOAuthAuthorizationCodeAccessToken() - Added 401 interceptor with user-friendly error messages 8. UI Components - useOAuthAuthorize hook - Calls authorize endpoint and opens popup - Updated connector flyout footer with "Authorize" button for OAuth connectors - checkOAuthAuthCode() helper to detect OAuth auth type 9. SharePoint Online Connector - Changed from undefined auth to oauth_authorization_code - Defaults for Microsoft OAuth endpoints (with {tenant-id} placeholder) - Scope: https://graph.microsoft.com/.default offline_access ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This was checked for breaking HTTP API changes, and any breaking changes have been approved by the breaking-change committee. The `release_note:breaking` label should be applied in these situations. - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) - [ ] Review the [backport guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing) and apply applicable `backport:*` labels. ### Identify risks Does this PR introduce any risks? For example, consider risks like hard to test bugs, performance regression, potential of data loss. Describe the risk, its severity, and mitigation for each identified risk. Invite stakeholders and evaluate how to proceed before merging. - [ ] [See some risk examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) - [ ] ... --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Lorena Bălan <lorena.balan@elastic.co>
## Summary Closes #252277 This PR will be merged into a feature branch
… space (#251873) ## Summary **TL;DR** Closes elastic/search-team#12683 * Added `spaceId` to the state object we store while user completes authorization. * While here, also fixing some SO tests broken by #246655 Tested by creating a new space, adding a new connector there, then authorizing it and using it in a workflow. All worked well end-to-end. 👌 <img width="681" height="960" alt="Screenshot 2026-02-05 at 17 10 18" src="https://github.com/user-attachments/assets/a3b83e1f-2d59-4eb1-880b-e21d4044716d" /> <img width="2554" height="907" alt="Screenshot 2026-02-05 at 17 10 08" src="https://github.com/user-attachments/assets/31909dcb-62a4-499f-924d-3df05ecab4de" /> #### Alternatives considered 1️⃣ Initially tried doing sth like ```typescript const spaceId = spaces ? spaces.spacesService.getSpaceId(req) : 'default'; const namespace = spaces.spacesService.spaceIdToNamespace(spaceId) ``` in both callback and authorize enpoints... but realised the first line was always returning `default` in callback, due to the redirect_uri not having the space prefix. 2️⃣ Went for storing `spaceId` in the state rather than encoding the namespace in the `redirect_uri` because that would mean the OAuth apps config would have to allow all possible redirect_uris, for each namespace, which isn't ideal UX. 3️⃣ Went for storing `spaceId` rather than `namespace` directly mainly for readability. Given `namespace: undefined` is an actual valid value, would've had to bypass the `omitBy` for this one field, which I think would've been confusing when reading the code. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
…nt params (#251717) ## Summary Fixes elastic/search-team#12682 While here, also fixing some SO tests broken by #246655 The Scout and AB tests should be fixed by merging latest `main` into feature branch. ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This was checked for breaking HTTP API changes, and any breaking changes have been approved by the breaking-change committee. The `release_note:breaking` label should be applied in these situations. - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) - [x] Review the [backport guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing) and apply applicable `backport:*` labels. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
… apis (#252262) ## Summary Resolves #250976 This PR introduces a new authMode attribute for connectors that allows configuring authentication modes as either shared (default) or per-user. This enables support for different authentication patterns where connectors can use: - **shared**: Single set of credentials shared across all users - **per-user**: Individual user credentials for personalized authentication **Note**: The `per-user` mode is primarily intended for OAuth-based connectors where each user will authenticate with their own account. Implementing the actual per-user credential storage and OAuth flows is not part of this PR. At this stage, both modes use the same single-credential storage. The `per-user` flag is a declaration of intent for future OAuth capabilities. ### Key Changes - Saved object schema: Introduced v2 schema with `authMode` field support - Data migration: Model version 2 automatically backfills `authMode: 'shared'` for existing connectors that have `config.authType `set ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) - [x] Review the [backport guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing) and apply applicable `backport:*` labels. ### Release note: Create a connector with auth_mode attribute --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Julian Gernun <17549662+jcger@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
…#252762) ## Summary Closes elastic/search-team#12900 --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
…le (#252929) ## Summary Resolves elastic/kibana-team#2803 <img width="3456" height="1372" alt="image (20)" src="https://github.com/user-attachments/assets/82bd25f9-5020-48d9-8115-381488d0f5d9" /> ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) - [x] Review the [backport guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing) and apply applicable `backport:*` labels. ### Release note:
This PR is part of a series of PRs, it will be merged into a feature branch ## Summary Closes #250979 ### User connector token SO Added a new saved object type user_connector_token so connector tokens (e.g. OAuth) can be stored per user (by profileUid) instead of only globally. Includes mappings, model versions, and encrypted SO registration. ### Token client split Replaced the single implementation with two clients and a facade: * SharedConnectorTokenClient – existing behavior; uses connector_token SO (shared tokens). * UserConnectorTokenClient – new; uses user_connector_token SO, keyed by profileUid + connectorId (and optional credentialType / tokenType). * ConnectorTokenClient – thin facade: if profileUid is set it delegates to the user client, otherwise to the shared client. Adds debug logging for which client is used. ### API Existing ConnectorTokenClient methods now accept an optional profileUid. When present, operations are personal (user SO); when absent, they stay shared. Token IDs use prefixes personal: / shared: so the facade can route updates/deletes correctly. ### Call sites OAuth callback (and other callers that have a user context) can pass profileUid so tokens are stored per user. No change for callers that don’t pass profileUid. ### Tests Added unit tests for SharedConnectorTokenClient and UserConnectorTokenClient; updated ConnectorTokenClient tests for the facade and delegation. Removed the old assertion on deleteConnectorTokens return value because the implementation now returns Promise<void> (refactor in this PR). ### Misc Explicit Promise<void> return types and small cleanups (e.g. token id validation) in the shared/user clients. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Christos Nasikas <xristosnasikas@gmail.com>
# Slack Data Source (MVP) ### What's introduced in this PR - A Slack v2 connector with three actions: - `searchMessages` - `sendMessage` - `resolveChannelId` (retained as a power-user action, no mapping to a Workflow) - Accepts an authorization token as a Bearer token (no OAuth flow yet) - The Slack Data Source definition with three workflow YAML files: - `search_messages.yml` - `send_messages.yml` ## A word about authorization This PR was originally meant to merge into the `connectors-auth-code-grant` [feature branch](#252369). However, in the spirit of keeping things moving and keeping PR sizes manageable, this Data Source is now targeting `main` and bypassing any OAuth flow for the time being. Getting an authorization token will thus require you to go through an OAuth playground to acquire it before copy/pasting it as a `Bearer` token during Slack v2 connector setup. **This is a temporary measure**. Once the auth code grant feature branch is merged + EARS Slack service is available, a follow-up PR will be made to wire up the correct OAuth flow, and the Bearer token authentication method will be removed. ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md) - [x] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) - [x] Review the [backport guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing) and apply applicable `backport:*` labels. ## Release notes A Slack Data Source for Workplace AI --------- Co-authored-by: Sean Story <sean.story@elastic.co> Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Lorena Bălan <lorena.balan@elastic.co> Co-authored-by: Julian Gernun <17549662+jcger@users.noreply.github.com> Co-authored-by: Arianna Laudazzi <arianna.laudazzi@elastic.co>
…low (#253606) ## Summary Replaces the old `useOAuthAuthorize` hook with a full set of OAuth lifecycle hooks, a refactored server-side callback route, and a new disconnect route for the connector authorization code grant flow. Changes include: - New `useConnectorOAuthConnect` hook supports two modes: `Redirect` and `NewTab` (opens provider in a new tab, listens for completion via `BroadcastChannel`). - New `useOAuthRedirectResult` hook detects OAuth completion from URL query params, broadcasts the result to the opener tab, and auto-closes the tab when applicable. - New `useConnectorOAuthDisconnect` hook and `POST .../connector/{id}/_oauth_disconnect` server route to remove stored OAuth tokens. - Refactored OAuth callback route with CSP-compliant callback page (external script via `data-*` attributes). - Updated edit connector flyout with Authorize/Disconnect actions and success/error toasts. - Shared constants, types, enums, and unit tests. ## Demo https://github.com/user-attachments/assets/32a7c619-7d48-49b8-92d2-634baed097ad ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md) - [x] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [x] This was checked for breaking HTTP API changes, and any breaking changes have been approved by the breaking-change committee. The `release_note:breaking` label should be applied in these situations. - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) - [x] Review the [backport guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing) and apply applicable `backport:*` labels. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
## Summary * Add missing unit test file * Fixed issue where expired oauth_state weren't being cleaned up
…a into connectors-auth-code-grant
47b9df6 to
1907ce9
Compare
20719b9 to
e7e0dd0
Compare
Thank you @florent-leborgne, I've created a follow up item #257715 |
## Summary State client was generating a PKCE code longer than recommended 128 characters. This should fix it.
…a into connectors-auth-code-grant
f6e060e to
f6ece32
Compare
tomsonpl
left a comment
There was a problem hiding this comment.
Defend workflows LGTM 👍
💚 Build Succeeded
Metrics [docs]Module Count
Public APIs missing comments
Async chunks
Page load bundle
Unknown metric groupsAPI count
References to deprecated APIs
Unreferenced deprecated APIs
History
|
gsoldevila
left a comment
There was a problem hiding this comment.
Changes in Saved Objects LGTM (code review only)
## Description
Currently, all Kibana connectors use a shared service account for
authentication. This approach lacks per user level access support, as it
does not distinguish between individual users and service account user
levels of permission. To support more secure, flexible, and user-aware
integrations, we need to introduce per-user authentication for
connectors in Kibana, alongside the existing service account method.
## 2-step release
As there are changes that require a 2-step release, this PR won't add
`oauth_authorization_code` auth type to any connector type. Therefore,
it won't be usable for now. The changes that require a 2-step release
are:
- we are adding `refreshTokenExpiresAt` to AAD for `connector_token` SO
- we are adding `refreshToken` as an encrypted attribute for
`connector_token` SO
## Config to run this locally
```
uiSettings:
overrides:
'workflows:ui:enabled': true
server.publicBaseUrl: 'http://localhost:5601'
```
Also, the auth type needs to be used in a connector. Reach out privately
to get the necessary info.
## Involved PRs:
- elastic#246655
- elastic#251873
- elastic#251717
- elastic#252566
- elastic#252104
- elastic#252307
- elastic#252262
- elastic#252501
- elastic#253606
- elastic#254589
- elastic#254916
- Rename rate limit kbn setting 15d2c19
- Fix refresh token 34708e5
---------
Co-authored-by: Sean Story <sean.story@elastic.co>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Lorena Bălan <lorena.balan@elastic.co>
Co-authored-by: Janki Salvi <117571355+js-jankisalvi@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Christos Nasikas <xristosnasikas@gmail.com>
Co-authored-by: Dennis Tismenko <dennis.tismenko@elastic.co>
## Description
Currently, all Kibana connectors use a shared service account for
authentication. This approach lacks per user level access support, as it
does not distinguish between individual users and service account user
levels of permission. To support more secure, flexible, and user-aware
integrations, we need to introduce per-user authentication for
connectors in Kibana, alongside the existing service account method.
## 2-step release
As there are changes that require a 2-step release, this PR won't add
`oauth_authorization_code` auth type to any connector type. Therefore,
it won't be usable for now. The changes that require a 2-step release
are:
- we are adding `refreshTokenExpiresAt` to AAD for `connector_token` SO
- we are adding `refreshToken` as an encrypted attribute for
`connector_token` SO
## Config to run this locally
```
uiSettings:
overrides:
'workflows:ui:enabled': true
server.publicBaseUrl: 'http://localhost:5601'
```
Also, the auth type needs to be used in a connector. Reach out privately
to get the necessary info.
## Involved PRs:
- elastic#246655
- elastic#251873
- elastic#251717
- elastic#252566
- elastic#252104
- elastic#252307
- elastic#252262
- elastic#252501
- elastic#253606
- elastic#254589
- elastic#254916
- Rename rate limit kbn setting 15d2c19
- Fix refresh token 34708e5
---------
Co-authored-by: Sean Story <sean.story@elastic.co>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Lorena Bălan <lorena.balan@elastic.co>
Co-authored-by: Janki Salvi <117571355+js-jankisalvi@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Christos Nasikas <xristosnasikas@gmail.com>
Co-authored-by: Dennis Tismenko <dennis.tismenko@elastic.co>
…k routes (#262292) ## Summary Closes #257715 Adds availability: { since: '9.4.0' } to the two public OAuth routes introduced in #252369 (OAuth 2.0 Authorization Code Grant): - GET /api/actions/connector/_oauth_callback - GET /api/actions/connector/_oauth_callback_script This ensures the generated API docs show "Added in 9.4" for both serverless and stack (non-serverless) documentation. The two internal routes (_start_oauth_flow, _oauth_disconnect) don't need this annotation — the framework only applies availability to public routes, and internal routes are excluded from the OAS output. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Description
Currently, all Kibana connectors use a shared service account for authentication. This approach lacks per user level access support, as it does not distinguish between individual users and service account user levels of permission. To support more secure, flexible, and user-aware integrations, we need to introduce per-user authentication for connectors in Kibana, alongside the existing service account method.
2-step release
As there are changes that require a 2-step release, this PR won't add
oauth_authorization_codeauth type to any connector type. Therefore, it won't be usable for now. The changes that require a 2-step release are:refreshTokenExpiresAtto AAD forconnector_tokenSOrefreshTokenas an encrypted attribute forconnector_tokenSOConfig to run this locally
Also, the auth type needs to be used in a connector. Reach out privately to get the necessary info.
Involved PRs: