Skip to content

[WorkplaceAI] Add authz code-grant flow in Stack Connectors V2#246655

Merged
lorenabalan merged 55 commits intoconnectors-auth-code-grantfrom
seanstory/oauth2-auth-code-flow
Feb 4, 2026
Merged

[WorkplaceAI] Add authz code-grant flow in Stack Connectors V2#246655
lorenabalan merged 55 commits intoconnectors-auth-code-grantfrom
seanstory/oauth2-auth-code-flow

Conversation

@seanstory
Copy link
Copy Markdown
Member

@seanstory seanstory commented Dec 16, 2025

Summary

Closes https://github.com/elastic/search-team/issues/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

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
  1. 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
  1. 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
  1. 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
  1. 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
  1. OAuth Token Requests
  • request_oauth_authorization_code_token.ts - Exchanges authorization code for tokens
  • request_oauth_refresh_token.ts - Refreshes access token
  1. Integration Points
  • Updated ActionsClient.getOAuthAccessToken() to support "authorization_code" type
  • Modified getAxiosInstanceWithAuth() to call getOAuthAuthorizationCodeAccessToken()
  • Added 401 interceptor with user-friendly error messages
  1. 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
  1. 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, uses sentence case text and includes i18n support
  • Documentation was added for features that require explanation or tutorials
  • Unit or functional tests 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
  • 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 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
  • Review the backport guidelines 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.

Replace console logging with loggers, add types

Clarify how the auth impl works

Correctly secure the callback endpoint

Style success and failure pages

Separate out concerns from the authorize route

linting
@lorenabalan lorenabalan self-assigned this Dec 22, 2025
@lorenabalan lorenabalan changed the title oauth2 authorization code grant flow for v2 connectors [WorkplaceAI] Add authz code-grant flow in Stack Connectors V2 Dec 29, 2025
@lorenabalan lorenabalan force-pushed the seanstory/oauth2-auth-code-flow branch from 0d8aeae to f8d37b4 Compare December 31, 2025 13:02
@lorenabalan
Copy link
Copy Markdown
Contributor

Additional changes:

  • made expiresIn optional throughout the token handling code (updating both the schema and the connectors that depend on it) - not all providers return expiresIn when providing a token
  • enhanced OAuth state object to contain a Kibana URL where the app will redirect after successful OAuth
  • added a task manager task to clean up stale OAuth state entries (runs every 30 mins)
  • implemented a rate limiter on /_oauth_authorize and /_oauth_callback endpoints
  • switched from rendering HTML templates to redirecting to actual success page - what do we want to do in case of error?
  • added v2 schema for rawConnectorTokenSchema
  • added support for a configurable redirectUri in the connector config so we can use that as the callback instead of hardcoding the Kibana URL (useful for EARS?)
  • other fixes like normalised the bearer token casing, adding configurable useBasicAuth to support more OAuth protocol implementations

Tested with Sharepoint & Notion connectors, both seem to work well! ✨

📣 Opening this to feedback and first round of reviews, while I chip away at unit tests and docs.

Open question: Is there a mechanism or plan for a mechanism for embedding certain config values into other values? For example, for Sharepoint, it would be nice to only expose a tenantId custom config in the schema of the connector spec, and the value of that gets pulled into the auth fields, e.g.:

Screenshot 2025-12-31 at 15 09 38 Screenshot 2025-12-31 at 15 11 32

@seanstory
Copy link
Copy Markdown
Member Author

switched from rendering HTML templates to redirecting to actual success page - what do we want to do in case of error?

I think a static error page might be a good first approach. Hopefully able to safely escape and display information about what may have gone wrong.

Copy link
Copy Markdown
Member Author

@seanstory seanstory left a comment

Choose a reason for hiding this comment

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

I'm only half done with my review (17 files to go), but my eyes are glazing over. Will tackle the rest next week.

Sorry that a lot of my comments are on my own AI slop :whistle-innocent:

.string()
.min(1, { message: i18n.OAUTH_CLIENT_SECRET_REQUIRED_MESSAGE })
.meta({ label: i18n.OAUTH_CLIENT_SECRET_LABEL, sensitive: true }),
// when using z.url() it doesn't allow for empty urls even if it's an optional field
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

worth filing a bug for that?

Comment on lines +347 to +348
const normalizedTokenType = startCase(tokenResult.tokenType);
const formattedToken = `${normalizedTokenType} ${tokenResult.accessToken}`;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Why are we adding Bearer to what we store? Shouldn't we just store the raw token, and let the client figure out how to shove the credential into the right header?

Copy link
Copy Markdown
Contributor

@lorenabalan lorenabalan Jan 12, 2026

Choose a reason for hiding this comment

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

Hmm yeah I agree it feels a bit awkward that we can't access the raw token after this. However, oauth client credentials also do this, and so does oauth jwt, so this would be a bigger refactor that maybe would be safer in a separate PR / with ResponseOps' blessing.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

ack - will defer to ResponseOps.

@lorenabalan lorenabalan changed the base branch from seanstory/add-sharepoint-fetcher to main January 9, 2026 08:44
Copy link
Copy Markdown
Contributor

@szwarckonrad szwarckonrad left a comment

Choose a reason for hiding this comment

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

DW (EDR Workflows) changes in 3 files LGTM!

@botelastic botelastic bot added the Team:Fleet Team label for Observability Data Collection Fleet team label Feb 4, 2026
@elasticmachine
Copy link
Copy Markdown
Contributor

Pinging @elastic/fleet (Team:Fleet)

@lorenabalan lorenabalan force-pushed the seanstory/oauth2-auth-code-flow branch from 0c91f17 to ceb3413 Compare February 4, 2026 13:26
@lorenabalan lorenabalan force-pushed the seanstory/oauth2-auth-code-flow branch from ceb3413 to f79a2b3 Compare February 4, 2026 14:22
@lorenabalan lorenabalan merged commit d5913de into connectors-auth-code-grant Feb 4, 2026
11 of 13 checks passed
@lorenabalan lorenabalan deleted the seanstory/oauth2-auth-code-flow branch February 4, 2026 14:51
@elasticmachine
Copy link
Copy Markdown
Contributor

elasticmachine commented Feb 4, 2026

💔 Build Failed

Failed CI Steps

Test Failures

  • [job] [logs] Jest Integration Tests #7 / checking changes on all registered encrypted SO types detecting changes to encryption registration definitions
  • [job] [logs] Jest Integration Tests #7 / checking changes on all registered encrypted SO types detecting changes to encryption registration definitions
  • [job] [logs] Jest Integration Tests #7 / checking changes on all registered encrypted SO types detecting new model versions in registered encrypted types
  • [job] [logs] Jest Integration Tests #7 / checking changes on all registered encrypted SO types detecting new model versions in registered encrypted types
  • [job] [logs] FTR Configs #110 / integrations When on the Trusted Apps list "before all" hook for "should not show page title if there is no trusted app"
  • [job] [logs] Scout: [ platform / streams_app-serverless-oblt ] plugin / serverless-oblt - Stream data processing - data sources management - should allow adding a new kql data source
  • [job] [logs] Scout: [ platform / streams_app-serverless-oblt ] plugin / serverless-oblt - Stream data processing - data sources management - should allow adding a new kql data source
  • [job] [logs] Scout: [ platform / streams_app-stateful ] plugin / should allow adding a new kql data source
  • [job] [logs] Scout: [ platform / streams_app-serverless-oblt ] plugin / should allow adding a new kql data source
  • [job] [logs] Scout: [ platform / streams_app-stateful ] plugin / should allow adding a new kql data source
  • [job] [logs] Scout: [ platform / streams_app-serverless-oblt ] plugin / should allow adding a new kql data source
  • [job] [logs] Scout: [ platform / streams_app-stateful ] plugin / stateful - Stream data processing - data sources management - should allow adding a new kql data source
  • [job] [logs] Scout: [ platform / streams_app-stateful ] plugin / stateful - Stream data processing - data sources management - should allow adding a new kql data source

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
stackConnectors 653 654 +1
triggersActionsUi 1235 1237 +2
workflowsManagement 1257 1258 +1
total +4

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
cloudConnect 38.0KB 38.0KB +19.0B
logstash 28.0KB 28.0KB +19.0B
profiling 360.9KB 360.9KB +19.0B
stackConnectors 1.1MB 1.1MB +1.2KB
streamsApp 1.7MB 1.7MB +176.0B
triggersActionsUi 1.6MB 1.6MB +2.5KB
workflowsManagement 1.4MB 1.4MB +706.0B
total +4.5KB

History

cc @lorenabalan

Copy link
Copy Markdown
Contributor

@jeramysoucy jeramysoucy left a comment

Choose a reason for hiding this comment

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

@seanstory @lorenabalan I see this PR already merged before we had a chance to review it. I have some concerns regarding the changes to encrypted objects here. I left a few comments, but I wanted to make sure you were aware of the implications described in this guide:
https://docs.elastic.dev/kibana-dev-docs/key-concepts/encrypted-saved-objects-intro

Could you have a look and assess if we need to revert this PR before the next serverless release?

Comment on lines +174 to +182
attributesToIncludeInAAD: new Set([
'state',
'connectorId',
'redirectUri',
'authorizationUrl',
'scope',
'createdAt',
'expiresAt',
'createdBy',
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 am sure you've probably already considered this, but just in case...
https://docs.elastic.dev/kibana-dev-docs/key-concepts/encrypted-saved-objects-intro#what-attributes-should-be-included-in-aad

  • An attribute cannot be removed from AAD once it is included, unless it can be altogether removed from the object type, or refactored with a new name.
  • An existing attribute cannot be added to AAD if it was not included in AAD when it was first defined and has already been populated.

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.

Ah good point. I wanna say most of these we do want as AAD but will think a bit more with the team to confirm.

encryptedSavedObjects.registerType({
type: CONNECTOR_TOKEN_SAVED_OBJECT_TYPE,
attributesToEncrypt: new Set(['token']),
attributesToEncrypt: new Set(['token', 'refreshToken']),
Copy link
Copy Markdown
Contributor

@jeramysoucy jeramysoucy Feb 5, 2026

Choose a reason for hiding this comment

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

When adding new encrypted attributes there are some considerations we have to make regarding model versions and serverless zero downtime upgrades: https://docs.elastic.dev/kibana-dev-docs/key-concepts/encrypted-saved-objects-intro#serverless-considerations. Specifically the need to wrap the model versions with the createModelVersion wrapper.

Did you already reference this guide? If not, could you have a look?

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.

Hmm I didn't see this guide (thanks for referencing!), but I did add a new model version that's captured by L134 above, under the savedObjects.registerType({...}). Is there something else I'm missing?
I'll come back to this in morning with fresh eyes.

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.

Nvm I think I see what I'm missing now, will address in a follow-up PR

export const rawConnectorTokenSchema = rawConnectorTokenSchemaV1.extends({
expiresAt: schema.maybe(schema.string()), // turned into an optional field
refreshToken: schema.maybe(schema.string()),
refreshTokenExpiresAt: schema.maybe(schema.string()),
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.

As these attributes are already part of AAD, or are an encrypted attribute of the SO (refreshToken), are there any considerations we need to make for serverless?

lorenabalan added a commit that referenced this pull request Feb 10, 2026
… 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>
lorenabalan added a commit that referenced this pull request Feb 10, 2026
…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>
dennis-tismenko pushed a commit to dennis-tismenko/kibana that referenced this pull request Feb 18, 2026
…ic#246655)

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:
elastic#246655 (comment)

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

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.

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>
dennis-tismenko pushed a commit to dennis-tismenko/kibana that referenced this pull request Feb 18, 2026
… space (elastic#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
elastic#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>
dennis-tismenko pushed a commit to dennis-tismenko/kibana that referenced this pull request Feb 18, 2026
…nt params (elastic#251717)

## Summary

Fixes elastic/search-team#12682

While here, also fixing some SO tests broken by
elastic#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>
lorenabalan added a commit that referenced this pull request Feb 26, 2026
…dations (#252104)

## Summary
Addressing
#246655 (review)
& #251873 (comment)

Changes:
* Reduced the AAD footprint of the `oauth_state` SO (this SO was first
introduced in the feature branch, so we don't need to issue a migration
for it, we can just iterate directly)
* Used `createModelVersion` wrapper (as per
[docs](https://docs.elastic.dev/kibana-dev-docs/key-concepts/encrypted-saved-objects-intro#migrations-backward-compatibility-and-serverless))
for `connector_token` SO. In the feature branch we had enhanced the
object by adding `refreshTokenExpiresAt` as a new AAD and `refreshToken`
as a new encrypted field. `expiresAt` was also turned into an optional
field.


## Testing
Tests run by default with the `oauth_authorization_code` feature flag
disabled. In order to check the tests with it enabled you need to modify
`x-pack/platform/plugins/shared/encrypted_saved_objects/integration_tests/ci_checks/check_registered_types.test.ts`
:
* bump `ESO_TYPES_COUNT` to 21 (the extra models registered are
`oauth_state` and `user_connector_token`)
* then update `beforeAll()` to contain
    ```typescript
        root = createRootWithCorePlugins(
{ xpack: { actions: { auth: { oauth_authorization_code: { enabled: true
} } } } },
          { oss: false }
        );
    ```
Run *both*
```
node scripts/jest_integration x-pack/platform/plugins/shared/encrypted_saved_objects/integration_tests/ci_checks/check_registered_types.test.ts -u
```
and 
```
node scripts/jest_integration src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts -u        
```
You should see updates to `toMatchInlineSnapshot` in the tests like 
```
-"connector_token": "16ca2154c13c5ee3d3a45b55d4ea6cd33aeaceaef3dc229b002d25470bfc9b3b",
+ "connector_token": "e446f5ff0fbf516f63398e474f126332b4c31e316daa613c6cb8c863400110c5",
...
+ "oauth_state": "b01289e5c133db9d4d802a2b838e43cce4a8399566dedb21de551da57c88894a",
...
+ "user_connector_token": "b443b022b46b79c0ff9fa674aecc64176a5fcbd09c2db2d9f050a6a88435732e",
```

⚠️⚠️⚠️ When we enable the feature by default, we'll probably also have
to update this [test
file](https://github.com/gsoldevila/kibana/blob/de9e6a5089482213c2e97b98c214bbc011cb817c/packages/kbn-check-saved-objects-cli/src/commands/types.ts#L46-L60)
(uncomment)

## Misc
**Old question**
What's not entirely clear to me is release strategy for the
[connectors-auth-code-grant](https://github.com/elastic/kibana/tree/connectors-auth-code-grant)
feature branch, given
https://docs.elastic.dev/kibana-dev-docs/key-concepts/encrypted-saved-objects-intro#serverless-considerations
> This will require 2 Serverless release stages. 
Release 1: Add the attribute to the ESO's attributesToIncludeInAAD. Do
not yet populate or use the new attribute. Release 2: Implement a Model
Version and wrap it in a call to createModelVersion, providing the
former EncryptedSavedObjectTypeRegistration as the input type, and the
new EncryptedSavedObjectTypeRegistration as the output type. Implement a
Model Version backfill change as needed. The attribute can safely be
populated in this release.

Do we need to first merge a small PR to `main` that adds the
`refreshTokenExpiresAt` field to the `connector_token` SO, then wait a
day and merge the rest of the feature branch?

**Answer**:
#252735 (review)

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
jcger added a commit that referenced this pull request Mar 18, 2026
## 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:

- #246655
- #251873
- #251717
- #252566
- #252104
- #252307
- #252262
- #252501
- #253606
- #254589
- #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>
qn895 pushed a commit to qn895/kibana that referenced this pull request Mar 18, 2026
## 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>
jeramysoucy pushed a commit to jeramysoucy/kibana that referenced this pull request Mar 26, 2026
## 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Team:Fleet Team label for Observability Data Collection Fleet team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants