Skip to content

[DO NOT CLOSE PR] Prepare demo project#255701

Draft
lorenabalan wants to merge 164 commits intomainfrom
lb/poc/revoke-with-ears
Draft

[DO NOT CLOSE PR] Prepare demo project#255701
lorenabalan wants to merge 164 commits intomainfrom
lb/poc/revoke-with-ears

Conversation

@lorenabalan
Copy link
Copy Markdown
Contributor

@lorenabalan lorenabalan commented Mar 3, 2026

Cherry-picked 63dacf5 (Google Calendar data source) & 566e3b4 (GMail data source) & f97e2af (fix for serverless deployments)

Fixed tests

Tried /revoke via EARS and reverted (see #255701 (review))

seanstory and others added 30 commits February 5, 2026 01:51
## 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.


![code-grant-flow](https://github.com/user-attachments/assets/a9c06f4f-287b-42ef-b7da-653c89ac6375)

**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>
…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>
@elastic elastic deleted a comment from elasticmachine Mar 17, 2026
@elastic elastic deleted a comment from github-actions bot Mar 17, 2026
@lorenabalan lorenabalan force-pushed the lb/poc/revoke-with-ears branch from ad9129b to 3602c3c Compare March 17, 2026 16:30
@lorenabalan lorenabalan force-pushed the lb/poc/revoke-with-ears branch from 3602c3c to f555c2e Compare March 17, 2026 16:32
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 17, 2026

Vale Linting Results

Summary: 2 warnings, 1 suggestion found

⚠️ Warnings (2)
File Line Rule Message
docs/reference/connectors-kibana/gmail-action-type.md 12 Elastic.Latinisms Latin terms and abbreviations are a common source of confusion. Use 'using' instead of 'via'.
docs/reference/connectors-kibana/gmail-action-type.md 58 Elastic.Latinisms Latin terms and abbreviations are a common source of confusion. Use 'for example' instead of 'e.g'.
💡 Suggestions (1)
File Line Rule Message
docs/reference/connectors-kibana/gmail-action-type.md 53 Elastic.Semicolons Use semicolons judiciously.

The Vale linter checks documentation changes against the Elastic Docs style guide.

To use Vale locally or report issues, refer to Elastic style guide for Vale.

@kibanamachine
Copy link
Copy Markdown
Contributor

Project deployed, see credentials at: https://buildkite.com/elastic/kibana-deploy-project-from-pr/builds/1087

lorenabalan added a commit that referenced this pull request Mar 31, 2026
## Summary

Closes elastic/search-team#12949

### Changes:

* introduced `getStoredTokenWithRefresh` to avoid duplicate logic
between ears and non-ears authz; the only real difference was how we
refreshed
* introduced "strategies" for axios instances to avoid too many `if
ears` branches in how we instantiate the instance
* added `xpack.actions.ears.url` config that points to the relevant base
EARS url; ⚠️ this needs to be populated in ES3 (and hosted) deployments,
like we did
https://github.com/elastic/serverless-gitops/blob/f51db9f789fe9ce1ea668e27970a4468b37ef7c2/services/kibana-controller/values/qa/default.yaml#L63
* added 2 new folders `lib/ears` and `lib/axios_auth_strategies` but
some files import from outer folder `lib`. I just compromised for that
over moving files and making the diff larger, though I'm still not sure
if it's the best folder split. The `lib` folder is quite unwieldy. 😅
* [Remove leftover
capitalize](89beff8)
- see
[thread](#253695 (comment))
* #257968

**++ Thank you CodeRabbit:**
* fixed interceptor logic for authz code grant & ears flow, so that on
retry & successful refresh, we _also_ update the headers on the
axiosInstance, for future requests ([Update axiosInstance headers for
future
requests](09f6ae7))
* fixed `useBasicAuth` logic in authz code grant in [Fix useBasicAuth
propagation](b395e81);
connectors that specify `tokenEndpointAuthMethod: 'client_secret_post'`
will now correctly send credentials in the request body instead of
always defaulting to HTTP Basic Auth when refreshing tokens via
`getToken`.

### Other considerations
* 🚫 `revoke` workflow kept out of scope of this PR ↔️ see
#255701 (review)
* ✨ We could maybe add nicer UI component to render for `ears` authz
type in the form (connector flyout); not a huge fan of the fact that
`scope` are treated like secrets and they reset to default after
clicking `Save`
* 👉 We should raise a follow-up PR to set EARS URL in ES3 deployments in
the `xpack.actions.ears.url` config (if everyone agrees on the name)
* **Serverless**:
elastic/serverless-gitops#81614
    * **ECH**: elastic/cloud#153459
* ❓ We have NO separate rate limits between EARS and normal Authz Grant
flow. Should we? I would say no because ultimately we reach 3rd party
provider so we can't have higher rate limits than vanilla flow. The name
of the current config `auth.oauth_authorization_code.rate_limits` kind
of implies there would be more rate limits per auth types.

## Testing

Enable EARS auth on Google Drive connector by adding the following lines
to `auth.type` in
`src/platform/packages/shared/kbn-connector-specs/src/specs/google_drive/google_drive.ts`:
```typescript
{
    type: 'ears',
    defaults: {
        provider: 'google',
        scope: 'https://www.googleapis.com/auth/drive.readonly',
    },
},
```

Update your `kibana.dev.yaml` to contain the following lines:

```yaml
server.publicBaseUrl: http://localhost:5601
xpack.actions.ears.url: https://elastic-auth-redirect-service.eu-west-1.aws.svc.qa.elastic.cloud

uiSettings:
  overrides:
    'workflows:ui:enabled': true

logging:
  loggers:
    - name: plugins.actions
      level: debug
      appenders: [default]
```

Start ES
```shell
yarn es serverless --projectType elasticsearch_search --kill
```

Start Kibana
```shell
yarn start --serverless=es
```
Try to create & authorise a Google Drive connector. Then run a workflow
such as

```yaml
version: '1'
name: 'sources.google_drive.search'
description: Search for files in Google Drive using Google's query syntax
tags: ['agent-builder-tool']
enabled: true
triggers:
  - type: manual
inputs:
  - name: query
    type: string
    description: "Google Drive search query. Examples: name contains 'budget' and trashed=false | fullText contains 'quarterly report' and mimeType='application/pdf' | 'me' in owners and modifiedTime > '2024-01-01' | mimeType='application/vnd.google-apps.folder' and trashed=false. Operators: contains, =, !=, <, >, <=, >=. Combine with 'and'/'or'. String values use single quotes. Add 'and trashed=false' to exclude trashed files."
  - name: pageSize
    type: number
    required: false
    description: Number of results to return (default 250, max 1000)
  - name: pageToken
    type: string
    required: false
    description: "Pagination token. Pass the 'nextPageToken' value from a previous response to get the next page. When nextPageToken is absent in the response, there are no more results."
  - name: orderBy
    type: string
    required: false
    description: "Sort order: 'createdTime', 'createdTime desc', 'modifiedTime', 'modifiedTime desc', 'name', or 'name desc'"
steps:
  - name: search_files
    type: google_drive.searchFiles
    connector-id: <ENTER YOUR CONNECTOR ID HERE!>
    with:
      query: "${{inputs.query}}"
      pageSize: ${{inputs.pageSize}}
      pageToken: "${{inputs.pageToken}}"
      orderBy: "${{inputs.orderBy}}"

```

### 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)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials - we have
separate elastic/search-team#13469 to track
this
- [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.

---------

Co-authored-by: Sean Story <sean.story@elastic.co>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Julian Gernun <17549662+jcger@users.noreply.github.com>
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>
Base automatically changed from lb/poc/ears-auth to main March 31, 2026 10:06
jeramysoucy pushed a commit to jeramysoucy/kibana that referenced this pull request Apr 1, 2026
## Summary

Closes elastic/search-team#12949

### Changes:

* introduced `getStoredTokenWithRefresh` to avoid duplicate logic
between ears and non-ears authz; the only real difference was how we
refreshed
* introduced "strategies" for axios instances to avoid too many `if
ears` branches in how we instantiate the instance
* added `xpack.actions.ears.url` config that points to the relevant base
EARS url; ⚠️ this needs to be populated in ES3 (and hosted) deployments,
like we did
https://github.com/elastic/serverless-gitops/blob/f51db9f789fe9ce1ea668e27970a4468b37ef7c2/services/kibana-controller/values/qa/default.yaml#L63
* added 2 new folders `lib/ears` and `lib/axios_auth_strategies` but
some files import from outer folder `lib`. I just compromised for that
over moving files and making the diff larger, though I'm still not sure
if it's the best folder split. The `lib` folder is quite unwieldy. 😅
* [Remove leftover
capitalize](elastic@89beff8)
- see
[thread](elastic#253695 (comment))
* elastic#257968

**++ Thank you CodeRabbit:**
* fixed interceptor logic for authz code grant & ears flow, so that on
retry & successful refresh, we _also_ update the headers on the
axiosInstance, for future requests ([Update axiosInstance headers for
future
requests](elastic@09f6ae7))
* fixed `useBasicAuth` logic in authz code grant in [Fix useBasicAuth
propagation](elastic@b395e81);
connectors that specify `tokenEndpointAuthMethod: 'client_secret_post'`
will now correctly send credentials in the request body instead of
always defaulting to HTTP Basic Auth when refreshing tokens via
`getToken`.

### Other considerations
* 🚫 `revoke` workflow kept out of scope of this PR ↔️ see
elastic#255701 (review)
* ✨ We could maybe add nicer UI component to render for `ears` authz
type in the form (connector flyout); not a huge fan of the fact that
`scope` are treated like secrets and they reset to default after
clicking `Save`
* 👉 We should raise a follow-up PR to set EARS URL in ES3 deployments in
the `xpack.actions.ears.url` config (if everyone agrees on the name)
* **Serverless**:
elastic/serverless-gitops#81614
    * **ECH**: elastic/cloud#153459
* ❓ We have NO separate rate limits between EARS and normal Authz Grant
flow. Should we? I would say no because ultimately we reach 3rd party
provider so we can't have higher rate limits than vanilla flow. The name
of the current config `auth.oauth_authorization_code.rate_limits` kind
of implies there would be more rate limits per auth types.

## Testing

Enable EARS auth on Google Drive connector by adding the following lines
to `auth.type` in
`src/platform/packages/shared/kbn-connector-specs/src/specs/google_drive/google_drive.ts`:
```typescript
{
    type: 'ears',
    defaults: {
        provider: 'google',
        scope: 'https://www.googleapis.com/auth/drive.readonly',
    },
},
```

Update your `kibana.dev.yaml` to contain the following lines:

```yaml
server.publicBaseUrl: http://localhost:5601
xpack.actions.ears.url: https://elastic-auth-redirect-service.eu-west-1.aws.svc.qa.elastic.cloud

uiSettings:
  overrides:
    'workflows:ui:enabled': true

logging:
  loggers:
    - name: plugins.actions
      level: debug
      appenders: [default]
```

Start ES
```shell
yarn es serverless --projectType elasticsearch_search --kill
```

Start Kibana
```shell
yarn start --serverless=es
```
Try to create & authorise a Google Drive connector. Then run a workflow
such as

```yaml
version: '1'
name: 'sources.google_drive.search'
description: Search for files in Google Drive using Google's query syntax
tags: ['agent-builder-tool']
enabled: true
triggers:
  - type: manual
inputs:
  - name: query
    type: string
    description: "Google Drive search query. Examples: name contains 'budget' and trashed=false | fullText contains 'quarterly report' and mimeType='application/pdf' | 'me' in owners and modifiedTime > '2024-01-01' | mimeType='application/vnd.google-apps.folder' and trashed=false. Operators: contains, =, !=, <, >, <=, >=. Combine with 'and'/'or'. String values use single quotes. Add 'and trashed=false' to exclude trashed files."
  - name: pageSize
    type: number
    required: false
    description: Number of results to return (default 250, max 1000)
  - name: pageToken
    type: string
    required: false
    description: "Pagination token. Pass the 'nextPageToken' value from a previous response to get the next page. When nextPageToken is absent in the response, there are no more results."
  - name: orderBy
    type: string
    required: false
    description: "Sort order: 'createdTime', 'createdTime desc', 'modifiedTime', 'modifiedTime desc', 'name', or 'name desc'"
steps:
  - name: search_files
    type: google_drive.searchFiles
    connector-id: <ENTER YOUR CONNECTOR ID HERE!>
    with:
      query: "${{inputs.query}}"
      pageSize: ${{inputs.pageSize}}
      pageToken: "${{inputs.pageToken}}"
      orderBy: "${{inputs.orderBy}}"

```

### 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)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials - we have
separate elastic/search-team#13469 to track
this
- [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.

---------

Co-authored-by: Sean Story <sean.story@elastic.co>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Julian Gernun <17549662+jcger@users.noreply.github.com>
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>
paulinashakirova pushed a commit to paulinashakirova/kibana that referenced this pull request Apr 2, 2026
## Summary

Closes elastic/search-team#12949

### Changes:

* introduced `getStoredTokenWithRefresh` to avoid duplicate logic
between ears and non-ears authz; the only real difference was how we
refreshed
* introduced "strategies" for axios instances to avoid too many `if
ears` branches in how we instantiate the instance
* added `xpack.actions.ears.url` config that points to the relevant base
EARS url; ⚠️ this needs to be populated in ES3 (and hosted) deployments,
like we did
https://github.com/elastic/serverless-gitops/blob/f51db9f789fe9ce1ea668e27970a4468b37ef7c2/services/kibana-controller/values/qa/default.yaml#L63
* added 2 new folders `lib/ears` and `lib/axios_auth_strategies` but
some files import from outer folder `lib`. I just compromised for that
over moving files and making the diff larger, though I'm still not sure
if it's the best folder split. The `lib` folder is quite unwieldy. 😅
* [Remove leftover
capitalize](elastic@89beff8)
- see
[thread](elastic#253695 (comment))
* elastic#257968

**++ Thank you CodeRabbit:**
* fixed interceptor logic for authz code grant & ears flow, so that on
retry & successful refresh, we _also_ update the headers on the
axiosInstance, for future requests ([Update axiosInstance headers for
future
requests](elastic@09f6ae7))
* fixed `useBasicAuth` logic in authz code grant in [Fix useBasicAuth
propagation](elastic@b395e81);
connectors that specify `tokenEndpointAuthMethod: 'client_secret_post'`
will now correctly send credentials in the request body instead of
always defaulting to HTTP Basic Auth when refreshing tokens via
`getToken`.

### Other considerations
* 🚫 `revoke` workflow kept out of scope of this PR ↔️ see
elastic#255701 (review)
* ✨ We could maybe add nicer UI component to render for `ears` authz
type in the form (connector flyout); not a huge fan of the fact that
`scope` are treated like secrets and they reset to default after
clicking `Save`
* 👉 We should raise a follow-up PR to set EARS URL in ES3 deployments in
the `xpack.actions.ears.url` config (if everyone agrees on the name)
* **Serverless**:
elastic/serverless-gitops#81614
    * **ECH**: elastic/cloud#153459
* ❓ We have NO separate rate limits between EARS and normal Authz Grant
flow. Should we? I would say no because ultimately we reach 3rd party
provider so we can't have higher rate limits than vanilla flow. The name
of the current config `auth.oauth_authorization_code.rate_limits` kind
of implies there would be more rate limits per auth types.

## Testing

Enable EARS auth on Google Drive connector by adding the following lines
to `auth.type` in
`src/platform/packages/shared/kbn-connector-specs/src/specs/google_drive/google_drive.ts`:
```typescript
{
    type: 'ears',
    defaults: {
        provider: 'google',
        scope: 'https://www.googleapis.com/auth/drive.readonly',
    },
},
```

Update your `kibana.dev.yaml` to contain the following lines:

```yaml
server.publicBaseUrl: http://localhost:5601
xpack.actions.ears.url: https://elastic-auth-redirect-service.eu-west-1.aws.svc.qa.elastic.cloud

uiSettings:
  overrides:
    'workflows:ui:enabled': true

logging:
  loggers:
    - name: plugins.actions
      level: debug
      appenders: [default]
```

Start ES
```shell
yarn es serverless --projectType elasticsearch_search --kill
```

Start Kibana
```shell
yarn start --serverless=es
```
Try to create & authorise a Google Drive connector. Then run a workflow
such as

```yaml
version: '1'
name: 'sources.google_drive.search'
description: Search for files in Google Drive using Google's query syntax
tags: ['agent-builder-tool']
enabled: true
triggers:
  - type: manual
inputs:
  - name: query
    type: string
    description: "Google Drive search query. Examples: name contains 'budget' and trashed=false | fullText contains 'quarterly report' and mimeType='application/pdf' | 'me' in owners and modifiedTime > '2024-01-01' | mimeType='application/vnd.google-apps.folder' and trashed=false. Operators: contains, =, !=, <, >, <=, >=. Combine with 'and'/'or'. String values use single quotes. Add 'and trashed=false' to exclude trashed files."
  - name: pageSize
    type: number
    required: false
    description: Number of results to return (default 250, max 1000)
  - name: pageToken
    type: string
    required: false
    description: "Pagination token. Pass the 'nextPageToken' value from a previous response to get the next page. When nextPageToken is absent in the response, there are no more results."
  - name: orderBy
    type: string
    required: false
    description: "Sort order: 'createdTime', 'createdTime desc', 'modifiedTime', 'modifiedTime desc', 'name', or 'name desc'"
steps:
  - name: search_files
    type: google_drive.searchFiles
    connector-id: <ENTER YOUR CONNECTOR ID HERE!>
    with:
      query: "${{inputs.query}}"
      pageSize: ${{inputs.pageSize}}
      pageToken: "${{inputs.pageToken}}"
      orderBy: "${{inputs.orderBy}}"

```

### 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)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials - we have
separate elastic/search-team#13469 to track
this
- [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.

---------

Co-authored-by: Sean Story <sean.story@elastic.co>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Julian Gernun <17549662+jcger@users.noreply.github.com>
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:project-deploy-elasticsearch Create an Elasticsearch Serverless project ci:project-persist-deployment Persist project deployment indefinitely

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants