Skip to content

Add GitHubActionsCredential for GitHub Actions OIDC federation#38581

Open
KarishmaGhiya wants to merge 1 commit into
Azure:mainfrom
KarishmaGhiya:kaghiya/github-actions-credential
Open

Add GitHubActionsCredential for GitHub Actions OIDC federation#38581
KarishmaGhiya wants to merge 1 commit into
Azure:mainfrom
KarishmaGhiya:kaghiya/github-actions-credential

Conversation

@KarishmaGhiya
Copy link
Copy Markdown
Member

Description

Implements a first-class \GitHubActionsCredential\ in @azure/identity\ that enables authentication to Microsoft Entra ID using GitHub Actions OIDC federated identity credentials.

Key Design Decisions

  • Parameterless constructor — reads \AZURE_TENANT_ID, \AZURE_CLIENT_ID, \ACTIONS_ID_TOKEN_REQUEST_URL, and \ACTIONS_ID_TOKEN_REQUEST_TOKEN\ from environment variables
  • *Delegates to \ClientAssertionCredential* — uses the OIDC JWT as the client assertion
  • *Audience derived from \�uthorityHost* — no public \�udience\ option; sovereign clouds (US Gov, China) are handled automatically
  • Fails eagerly — throws \CredentialUnavailableError\ in constructor when env vars are missing, enabling fast skip in \ChainedTokenCredential\
  • Not added to DefaultAzureCredential — ships standalone first; DAC integration deferred to future release

Files Added

  • \src/credentials/gitHubActionsCredential.ts\ — main credential implementation
  • \src/credentials/gitHubActionsCredential-browser.mts\ — browser stub
  • \src/credentials/gitHubActionsCredentialOptions.ts\ — options interface
  • \ est/internal/node/gitHubActionsCredential.spec.ts\ — internal unit tests (10 tests)
  • \ est/public/node/gitHubActionsCredential.spec.ts\ — public API tests (6 tests)

Files Modified

  • \src/index.ts\ — added exports
  • \CHANGELOG.md\ — documented new feature

Testing

  • All 16 unit tests pass
  • TypeScript compiles clean (\ sc --noEmit)

Consumers

Azure CLI, Azure PowerShell, and Azure Developer CLI teams (~559K OIDC logins/month from GitHub Actions).

Implements a first-class GitHubActionsCredential in @azure/identity that
enables authentication to Microsoft Entra ID using GitHub Actions OIDC
federated identity credentials.

- Parameterless constructor reads AZURE_TENANT_ID, AZURE_CLIENT_ID,
  ACTIONS_ID_TOKEN_REQUEST_URL, and ACTIONS_ID_TOKEN_REQUEST_TOKEN from env
- Delegates to ClientAssertionCredential with OIDC token as assertion
- Derives audience from authorityHost for sovereign cloud support
- Fails eagerly with CredentialUnavailableError when env vars are missing
- Includes browser stub, unit tests, and public API tests

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@KarishmaGhiya KarishmaGhiya force-pushed the kaghiya/github-actions-credential branch from f62bb33 to 68c8bbc Compare May 19, 2026 01:20
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a first-class GitHubActionsCredential to @azure/identity that authenticates to Microsoft Entra ID using GitHub Actions OIDC federated identity. The credential reads AZURE_TENANT_ID, AZURE_CLIENT_ID, ACTIONS_ID_TOKEN_REQUEST_URL, and ACTIONS_ID_TOKEN_REQUEST_TOKEN from the environment, requests an OIDC JWT from the runner, and delegates token acquisition to ClientAssertionCredential. Sovereign cloud audiences are derived automatically from authorityHost.

Changes:

  • New Node-only GitHubActionsCredential (with browser stub) plus options interface, exported from the package entry point.
  • deriveAudience helper mapping authorityHostapi://AzureADTokenExchange[USGov|China]; handleOidcResponse parses GitHub's {value: ...} response.
  • Adds unit/public tests, a CHANGELOG entry, and an unrelated CODEOWNERS entry for /sdk/postgresql/postgresql-auth/.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
sdk/identity/identity/src/credentials/gitHubActionsCredential.ts Main credential implementation, OIDC request, audience derivation, response parsing
sdk/identity/identity/src/credentials/gitHubActionsCredential-browser.mts Browser stub that throws BrowserNotSupportedError
sdk/identity/identity/src/credentials/gitHubActionsCredentialOptions.ts Options interface extending standard credential option mixins
sdk/identity/identity/src/index.ts Public exports for the new credential and its options
sdk/identity/identity/CHANGELOG.md Documents the new feature under 4.14.0-beta.3
sdk/identity/identity/test/internal/node/gitHubActionsCredential.spec.ts Unit tests for handleOidcResponse and deriveAudience
sdk/identity/identity/test/public/node/gitHubActionsCredential.spec.ts Public-API tests for env-var validation and successful construction
.github/CODEOWNERS Unrelated CODEOWNERS entry for /sdk/postgresql/postgresql-auth/

Comment on lines +151 to +157
let url = oidcRequestUrl;
if (audience) {
url = `${oidcRequestUrl}&audience=${encodeURIComponent(audience)}`;
}

const request = createPipelineRequest({
url,
Comment thread .github/CODEOWNERS
Comment on lines 277 to 279
* - `ACTIONS_ID_TOKEN_REQUEST_TOKEN` — Set automatically by GitHub Actions runner.
*/
export class GitHubActionsCredential implements TokenCredential {
private clientAssertionCredential: ClientAssertionCredential | undefined;
Comment on lines +185 to +210
try {
const result = JSON.parse(text);
if (result?.value) {
return result.value;
} else {
const errorMessage = `${credentialName}: Authentication Failed. "value" field not detected in the response.`;
let errorDescription = "";
if (response.status !== 200) {
errorDescription = `Response body = ${text}. Status code: ${response.status}. See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/githubactionscredential/troubleshoot`;
}
logger.error(errorMessage);
logger.error(errorDescription);
throw new AuthenticationError(response.status, {
error: errorMessage,
error_description: errorDescription,
});
}
} catch (e: any) {
if (e instanceof AuthenticationError) throw e;
const errorDetails = `${credentialName}: Authentication Failed. Failed to parse OIDC response. Response = ${text}. Error: ${e.message}`;
logger.error(errorDetails);
throw new AuthenticationError(response.status, {
error: errorDetails,
error_description: `See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/githubactionscredential/troubleshoot`,
});
}
Comment on lines +104 to +106
logger.info(
`Invoking GitHubActionsCredential with tenant ID: ${tenantId}, client ID: ${clientId}, audience: ${audience}`,
);
Comment on lines +142 to +166
private async requestOidcToken(
oidcRequestUrl: string,
oidcRequestToken: string,
audience: string,
): Promise<string> {
logger.info("Requesting OIDC token from GitHub Actions...");

// GitHub OIDC endpoint uses GET (not POST like Azure Pipelines).
// Audience is appended as query param; omit if empty.
let url = oidcRequestUrl;
if (audience) {
url = `${oidcRequestUrl}&audience=${encodeURIComponent(audience)}`;
}

const request = createPipelineRequest({
url,
method: "GET",
headers: createHttpHeaders({
Authorization: `Bearer ${oidcRequestToken}`,
}),
});

const response = await this.identityClient.sendRequest(request);
return handleOidcResponse(response);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Untriaged

Development

Successfully merging this pull request may close these issues.

2 participants