Skip to content

feat: add Azure Federated Workload Identity support for OIDC SSO login#7966

Open
cosmincatalin wants to merge 6 commits intographql-hive:mainfrom
cosmincatalin:main
Open

feat: add Azure Federated Workload Identity support for OIDC SSO login#7966
cosmincatalin wants to merge 6 commits intographql-hive:mainfrom
cosmincatalin:main

Conversation

@cosmincatalin
Copy link
Copy Markdown

Background

When deployed in Kubernetes with Azure Workload Identity, the OIDC SSO integration should be able to authenticate to the identity provider (e.g., Microsoft Entra ID) using a federated token (client_assertion) instead of storing a client_secret. This eliminates the need for secrets management for the OAuth2 token exchange.

Description

Adds a useFederatedCredential option to OIDC integrations. When enabled, the token exchange uses the AZURE_FEDERATED_TOKEN_FILE (injected by the Azure Workload Identity webhook) as a client_assertion JWT bearer instead of client_secret.

  • DB migration: use_federated_credential boolean column on oidc_integrations, client_secret made nullable
  • Storage/Entity: OIDCIntegration.encryptedClientSecret now string | null, added useFederatedCredential: boolean
  • GraphQL schema: clientSecret optional in CreateOIDCIntegrationInput, useFederatedCredential field on type + inputs
  • OIDC provider: Validates that either clientSecret or useFederatedCredential is provided on create
  • Auth server token exchange (supertokens-at-home.ts): Reads federated token file and sends client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer + client_assertion=<token> instead of client_secret
  • UI: Shows federated credential status badge, handles nullable clientSecretPreview

Token exchange with federated credentials:

POST /token
  grant_type=authorization_code
  client_id=<app-registration-client-id>
  client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
  client_assertion=<contents-of-AZURE_FEDERATED_TOKEN_FILE>
  code=<auth-code>
  code_verifier=<pkce-verifier>

#2)

* feat: add Azure Federated Identity (OAuthBearer) support for Kafka/EventHub

Add support for the `oauthbearer` SASL mechanism in both the usage and
usage-ingestor services, enabling Azure Workload Identity authentication
to Event Hub when deployed in Kubernetes.

Changes:
- Add `@azure/identity` dependency to usage and usage-ingestor packages
- Add `oauthbearer` SASL mechanism to environment config (Zod schemas)
- Create `oauth-bearer-provider.ts` using DefaultAzureCredential
- Update Kafka client initialization to support oauthbearer mechanism
- Update Pulumi deployment to conditionally configure oauthbearer

Agent-Logs-Url: https://github.com/cosmincatalin/console/sessions/b3983d22-e4bf-4a52-90f1-c93895adeff8

Co-authored-by: cosmincatalin <525590+cosmincatalin@users.noreply.github.com>

* refactor: improve OAuth bearer provider error handling and documentation

Agent-Logs-Url: https://github.com/cosmincatalin/console/sessions/b3983d22-e4bf-4a52-90f1-c93895adeff8

Co-authored-by: cosmincatalin <525590+cosmincatalin@users.noreply.github.com>

* revert: remove incorrect Kafka OAuthBearer changes

Agent-Logs-Url: https://github.com/cosmincatalin/console/sessions/755ee5ba-e92c-4df8-b742-e04e182b5a13

Co-authored-by: cosmincatalin <525590+cosmincatalin@users.noreply.github.com>

* feat: add Azure Federated Workload Identity support for OIDC SSO login

When deployed in Kubernetes with Azure Workload Identity, the OIDC
integration can now authenticate to the identity provider using a
federated token (client_assertion) instead of a client_secret.

Changes:
- DB migration: add use_federated_credential column, make client_secret nullable
- Entity/model: update OIDCIntegration to include useFederatedCredential
- GraphQL: make clientSecret optional in create input, add useFederatedCredential field
- OIDC provider: allow creation without client secret when federated
- Auth server: use client_assertion with AZURE_FEDERATED_TOKEN_FILE
- UI: show federated credential status, allow saving without client secret

Agent-Logs-Url: https://github.com/cosmincatalin/console/sessions/755ee5ba-e92c-4df8-b742-e04e182b5a13

Co-authored-by: cosmincatalin <525590+cosmincatalin@users.noreply.github.com>

* fix: use strict equality for null check in OIDC provider

Agent-Logs-Url: https://github.com/cosmincatalin/console/sessions/755ee5ba-e92c-4df8-b742-e04e182b5a13

Co-authored-by: cosmincatalin <525590+cosmincatalin@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: cosmincatalin <525590+cosmincatalin@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for OIDC federated credentials, specifically Azure Workload Identity, allowing authentication without a client secret. Key changes include database migrations to make client secrets optional, GraphQL schema updates, and server-side logic to utilize federated token files during token exchange. Feedback highlights a style guide violation regarding direct process.env access, a performance concern with synchronous file I/O in an asynchronous handler, and a missing validation check in the update logic to ensure a valid authentication method is always configured.

cosmincatalin and others added 4 commits April 11, 2026 16:55
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…irect process.env access (#3)

Agent-Logs-Url: https://github.com/cosmincatalin/console/sessions/8b554117-9357-40a5-9879-83f5ac168987

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: cosmincatalin <525590+cosmincatalin@users.noreply.github.com>
* Add validation in updateOIDCIntegration to ensure valid auth method after update

Agent-Logs-Url: https://github.com/cosmincatalin/console/sessions/3b791a1d-2b1b-4152-af23-11dcd32bc977

Co-authored-by: cosmincatalin <525590+cosmincatalin@users.noreply.github.com>

* Improve error message for missing auth method validation

Agent-Logs-Url: https://github.com/cosmincatalin/console/sessions/3b791a1d-2b1b-4152-af23-11dcd32bc977

Co-authored-by: cosmincatalin <525590+cosmincatalin@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: cosmincatalin <525590+cosmincatalin@users.noreply.github.com>
@cosmincatalin
Copy link
Copy Markdown
Author

@n1ru4l, with #7745 in, can you look into merging this one in?

Copy link
Copy Markdown
Contributor

@n1ru4l n1ru4l left a comment

Choose a reason for hiding this comment

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

Thank you for this contribution! I added some initial comments with an initial review, it would be great if you could address these. We cannot give an exact timeline yet, but we will try to test this on our cluster and see if it feasible to merge and support soon.

Comment on lines +1322 to +1339
const tokenFilePath = process.env['AZURE_FEDERATED_TOKEN_FILE'];
if (!tokenFilePath) {
req.log.error('AZURE_FEDERATED_TOKEN_FILE environment variable is not set');
broadcastLog(
oidcIntegration.id,
'Federated credential is configured but AZURE_FEDERATED_TOKEN_FILE environment variable is not set. ' +
'Ensure the pod has Azure Workload Identity configured.',
);
return rep.status(200).send({
status: 'SIGN_IN_UP_NOT_ALLOWED',
reason: 'Sign in failed. Please contact your organization administrator.',
});
}

const { readFileSync } = await import('node:fs');
const federatedToken = readFileSync(tokenFilePath, 'utf-8');
grantParams['client_assertion_type'] =
'urn:ietf:params:oauth:client-assertion-type:jwt-bearer';
Copy link
Copy Markdown
Contributor

@n1ru4l n1ru4l Apr 10, 2026

Choose a reason for hiding this comment

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

Can you please move the token file reading to the environment.ts file and model the configuration in a way that would allow also configuring other providers in the future (for self-hosters)?

E.g. the environment variable could look like the following:

OIDC_WORKLOAD_FEDERATION_IDENTITY_PROVIDER="azure"

Which then implies that we have to setup some job that polls the path at that env[AZURE_FEDERATED_TOKEN_FILE] in intervals?

Also I think it would be safe to fail service startup if OIDC_WORKLOAD_FEDERATION_IDENTITY_PROVIDER is provided but AZURE_FEDERATED_TOKEN_FILE is not set to a file path or cannot be read?

Attempting to read the tokenFilePath every time a request is authenticated seems a lot, so maybe we can have a container class/service that just polls or watches the file path?

Comment on lines +1325 to +1329
broadcastLog(
oidcIntegration.id,
'Federated credential is configured but AZURE_FEDERATED_TOKEN_FILE environment variable is not set. ' +
'Ensure the pod has Azure Workload Identity configured.',
);
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.

This is an internal implementation detail that should not be leaked to the outside world.

Comment on lines +6 to +10
ALTER TABLE "oidc_integrations"
ADD COLUMN IF NOT EXISTS "use_federated_credential" BOOLEAN NOT NULL DEFAULT FALSE;

ALTER TABLE "oidc_integrations"
ALTER COLUMN "client_secret" DROP NOT NULL;
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.

NIT: this can be combined into a single statement

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants