Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 29, 2026

Implementation Complete: ****** Authentication Support

  • Understand current authentication flow and priorities
  • Add access token field to KeyVaultClient
  • Modify obtainAccessToken to support bearer tokens with proper priority (Managed Identity > Access Token > Client Credentials)
  • Update createKeyVaultClientBySystemProperty to read access-token property
  • Update KeyVaultKeyStore constructor to read and pass access-token property
  • Update KeyVaultCertificates to support access-token parameter
  • Update KeyVaultLoadStoreParameter to include access-token
  • Add AccessToken constructor for bearer token support
  • Update README.md documentation with property listing
  • Add comprehensive tests for access token authentication
  • Fix checkstyle issues (make providedAccessToken final)
  • Build and test changes - All 83 tests passing
  • Verify checkstyle and spotbugs pass
  • Update CHANGELOG.md with new feature
  • Address all code review feedback:
    • Set token expiration to effectively infinite to prevent auto-refresh attempts
    • Added empty string validation for providedAccessToken
    • Removed unused constructor
    • Removed usage example section from README (will be added in PR Add Workload Identity Auth Support in KV JCA #47051)
    • Removed authentication priority section from README (will be added in PR Add Workload Identity Auth Support in KV JCA #47051)
    • Kept providedAccessToken field name for clarity
    • Renamed getAccessTokenByHttpRequest to obtainAccessToken for accuracy

Summary

This PR adds support for bearer token authentication via the new azure.keyvault.access-token system property. This enhancement enables users to:

  1. Use pre-obtained access tokens for authentication without providing client credentials
  2. Receive clear authentication errors when tokens expire (no auto-refresh mechanism)
  3. Maintain proper authentication priority: Managed Identity > Access Token > Client Credentials

Changes Made

Core Implementation:

  • Added providedAccessToken field to KeyVaultClient with proper authentication priority logic
  • Implemented empty string validation for access tokens
  • Set expiration to Long.MAX_VALUE / 1000 (effectively infinite) to prevent futile auto-refresh attempts
  • When provided tokens expire on Azure's side, authentication requests fail with runtime exceptions, informing users to provide fresh tokens
  • Updated KeyVaultLoadStoreParameter to accept and pass access tokens through the main constructor
  • Modified KeyVaultCertificates and KeyVaultKeyStore to support the new authentication method
  • Added constructor to AccessToken model for creating instances from provided tokens
  • Renamed getAccessTokenByHttpRequest to obtainAccessToken to accurately reflect its behavior

Documentation:

  • Updated README.md with new property in the configuration list
  • Added CHANGELOG.md entry documenting the new feature

Testing:

  • Added unit tests for access token authentication (testAccessTokenAuthentication)
  • Added tests verifying authentication priority order (testAuthenticationPriority)
  • All 83 existing tests continue to pass

Authentication Priority

The implementation ensures the following priority order in code:

  1. Managed Identity (azure.keyvault.managed-identity) - Highest priority
  2. Access Token (azure.keyvault.access-token) - Middle priority
  3. Client Credentials (azure.keyvault.client-id + azure.keyvault.client-secret) - Lowest priority

Token Lifecycle

Provided access tokens do not auto-refresh. The token is set with effectively infinite expiration to prevent the code from attempting to refresh it. When the actual token expires on Azure's side, authentication requests will fail with runtime exceptions, which correctly informs users they need to provide a fresh token through the azure.keyvault.access-token system property.

Original prompt

This section details on the original issue you should resolve

<issue_title>[FEATURE REQ] azure-security-keyvault-jca should support bearer tokens</issue_title>
<issue_description>Is your feature request related to a problem? Please describe.
I would like to be able to use an Azure accessToken as a means for authentication when using the azure-security-keyvault-jca in the same manner that the azuresigntool allows with the command line -kva option, while not having to supply a client ID and client secret.

Describe the solution you'd like
I would like to have an exposed option for the azure-security-keyvault-jca of azure.keyvault.accesstoken in which I can utilize an access token for authentication, instead of having to supply the client ID and client secret. This would allow me to programmatically utilize multi-factor authentication for my code signing needs by first authenticating my service principal to Azure utilizing only a certificate (something I have), requesting a temporary access token, then utilizing that temporary access token (something I know) to perform my code signings utilizing the azure-security-keyvault-jca.

Describe alternatives you've considered
Utilizing the current azure-security-keyvault-jca authentication option of supplying client ID and client secret works, but it does not provide me with multi-factor authentication. Also my code signing servers are standalone and are not integrated to my Microsoft Entra ID so I cant utilize managed identities.

Additional context
N/A

Information Checklist
Kindly make sure that you have added all the following information above and checkoff the required fields otherwise we will treat the issuer as an incomplete report

  • Description Added
  • Expected solution specified
    </issue_description>

<agent_instructions>Support new property: "azure.keyvault.access-token", its priority should below "azure.keyvault.managed-identity", but above "azure.keyvault.client-id" and "azure.keyvault.client-secret".</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@joshfree Hi @GuzDaMan thank you for reaching out to us via GitHub. I've routed your feature request to the KV SDK owner, @vcolin7 to reply with more details. /cc @chlowell @vcolin7 @saragluna, @rujche would you mind taking a look at this issue when you get a chance? Thanks!

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 4 commits January 29, 2026 06:52
…ken property

Co-authored-by: rujche <171773178+rujche@users.noreply.github.com>
Co-authored-by: rujche <171773178+rujche@users.noreply.github.com>
Co-authored-by: rujche <171773178+rujche@users.noreply.github.com>
…mprove docs

Co-authored-by: rujche <171773178+rujche@users.noreply.github.com>
Copilot AI changed the title [WIP] Add support for bearer tokens in azure-security-keyvault-jca Add bearer token authentication support via azure.keyvault.access-token Jan 29, 2026
Copilot AI requested a review from rujche January 29, 2026 07:05
…ameter

Co-authored-by: rujche <171773178+rujche@users.noreply.github.com>
Copilot AI requested a review from rujche January 29, 2026 07:57
…w feedback

Co-authored-by: rujche <171773178+rujche@users.noreply.github.com>
Copilot AI requested a review from rujche January 29, 2026 08:02
…ble naming

Co-authored-by: rujche <171773178+rujche@users.noreply.github.com>
…ed refresh attempts

Co-authored-by: rujche <171773178+rujche@users.noreply.github.com>
Co-authored-by: rujche <171773178+rujche@users.noreply.github.com>
Copilot AI requested a review from rujche January 29, 2026 08:28
@rujche rujche marked this pull request as ready for review January 29, 2026 09:10
@rujche rujche requested review from a team, Netyyyy, moarychan and saragluna as code owners January 29, 2026 09:10
Copilot AI review requested due to automatic review settings January 29, 2026 09:10
@rujche
Copy link
Member

rujche commented Jan 29, 2026

/azp run java - keyvault tests

@azure-pipelines
Copy link

No pipelines are associated with this pull request.

@rujche rujche added azure-spring All azure-spring related issues azure-spring-jca labels Jan 29, 2026
@rujche rujche moved this from Todo to In Progress in Spring Cloud Azure Jan 29, 2026
@rujche rujche added this to the 2026-02 milestone Jan 29, 2026
@rujche
Copy link
Member

rujche commented Jan 29, 2026

Confirmed the unit test work as expected:

Image
Image
Image

@rujche rujche changed the title Add bearer token authentication support via azure.keyvault.access-token Support azure.keyvault.access-token in azure-security-keyvault-jca Jan 29, 2026
Copy link
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

This pull request adds support for bearer token authentication via the new azure.keyvault.access-token system property to the Azure Key Vault JCA library. This enhancement enables users to provide pre-obtained access tokens for authentication without requiring client credentials, supporting multi-factor authentication scenarios.

Changes:

  • Added bearer token authentication support with proper authentication priority: Managed Identity > Access Token > Client Credentials
  • Implemented token lifecycle management where provided tokens don't auto-refresh, and expiration is handled by Azure returning authentication errors
  • Consolidated and improved test coverage for Key Vault client authentication scenarios

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/KeyVaultClient.java Added providedAccessToken field and authentication priority logic in obtainAccessToken method; renamed getAccessTokenByHttpRequest to obtainAccessToken
sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultLoadStoreParameter.java Added accessToken field and constructor parameter to support passing access tokens
sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultKeyStore.java Updated to read azure.keyvault.access-token system property and pass to KeyVaultCertificates
sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificates.java Added accessToken parameter to constructors and updateKeyVaultClient methods
sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/model/AccessToken.java Added constructor accepting accessToken and expiresIn parameters for creating AccessToken instances from provided tokens
sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/KeyVaultClientTest.java Added comprehensive tests for access token authentication and authentication priority; consolidated integration tests from removed file
sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultClientTest.java Removed duplicate test file; tests consolidated into implementation package
sdk/keyvault/azure-security-keyvault-jca/README.md Added documentation for the new azure.keyvault.access-token property
sdk/keyvault/azure-security-keyvault-jca/CHANGELOG.md Added feature entry describing bearer token authentication support


@EnabledIfEnvironmentVariable(named = "AZURE_KEYVAULT_CERTIFICATE_NAME", matches = "myalias")
@Test
public void testKeuVaultClients() {
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The method name contains a typo. "Keu" should be "Key".

Suggested change
public void testKeuVaultClients() {
public void testKeyVaultClients() {

Copilot uses AI. Check for mistakes.
Comment on lines +206 to +240
public void testAuthenticationPriority() {
try (MockedStatic<HttpUtil> httpUtilMockedStatic = Mockito.mockStatic(HttpUtil.class);
MockedStatic<AccessTokenUtil> tokenUtilMockedStatic = Mockito.mockStatic(AccessTokenUtil.class)) {

httpUtilMockedStatic.when(() -> HttpUtil.validateUri(anyString(), anyString())).thenCallRealMethod();
httpUtilMockedStatic.when(() -> HttpUtil.addTrailingSlashIfRequired(anyString())).thenCallRealMethod();

AccessToken accessToken = new AccessToken("fake-token", 3600);
tokenUtilMockedStatic.when(() -> AccessTokenUtil.getAccessToken(anyString(), anyString()))
.thenReturn(accessToken);

CertificateItem fakeCertificateItem = new CertificateItem();
fakeCertificateItem.setId("certificates/fakeCertificateItem");

CertificateListResult certificateListResult = new CertificateListResult();
certificateListResult.setValue(Arrays.asList(fakeCertificateItem));

String certificateListResultString = JsonConverterUtil.toJson(certificateListResult);
httpUtilMockedStatic.when(() -> HttpUtil.get(anyString(), anyMap()))
.thenReturn(certificateListResultString);

// Test 1: Managed Identity should take priority over access token
KeyVaultClient client1
= new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null, null, null, "managed-id", "bearer-token", false);
client1.getAliases();
tokenUtilMockedStatic.verify(() -> AccessTokenUtil.getAccessToken(anyString(), eq("managed-id")), times(1));

// Test 2: Access token should be used when managed identity is not set
KeyVaultClient client2
= new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null, null, null, null, "bearer-token", false);
List<String> result = client2.getAliases();
assertEquals(1, result.size());
assertTrue(result.contains("fakeCertificateItem"));
}
}
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The authentication priority test only verifies two scenarios: managed identity over access token, and access token alone. However, it's missing a test case to verify that access token takes priority over client credentials (client ID/secret). Consider adding a third test case with client credentials present alongside an access token to ensure the access token is used instead of client credentials.

Copilot uses AI. Check for mistakes.
Comment on lines +176 to +203
@Test
public void testAccessTokenAuthentication() {
try (MockedStatic<HttpUtil> httpUtilMockedStatic = Mockito.mockStatic(HttpUtil.class)) {
httpUtilMockedStatic.when(() -> HttpUtil.validateUri(anyString(), anyString())).thenCallRealMethod();
httpUtilMockedStatic.when(() -> HttpUtil.addTrailingSlashIfRequired(anyString())).thenCallRealMethod();

CertificateItem fakeCertificateItem = new CertificateItem();
fakeCertificateItem.setId("certificates/fakeCertificateItem");

CertificateListResult certificateListResult = new CertificateListResult();
certificateListResult.setValue(Arrays.asList(fakeCertificateItem));

String certificateListResultString = JsonConverterUtil.toJson(certificateListResult);
httpUtilMockedStatic.when(() -> HttpUtil.get(anyString(), anyMap()))
.thenReturn(certificateListResultString);

// Create client with access token
String testAccessToken = "test-bearer-token-12345";
KeyVaultClient keyVaultClient
= new KeyVaultClient(KEY_VAULT_TEST_URI_GLOBAL, null, null, null, null, testAccessToken, false);

List<String> result = keyVaultClient.getAliases();

// Verify that the access token was used
assertEquals(1, result.size());
assertTrue(result.contains("fakeCertificateItem"));
}
}
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

Consider adding a test case to verify that an empty string access token is treated as if no access token was provided. This would ensure the empty string validation at line 230 in KeyVaultClient.java works correctly and falls back to client credentials when available.

Copilot uses AI. Check for mistakes.
@@ -51,10 +51,16 @@ public final class KeyVaultCertificates implements AzureCertificates {

public KeyVaultCertificates(long refreshInterval, String keyVaultUri, String tenantId, String clientId,
Copy link
Member

Choose a reason for hiding this comment

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

should we remove the old one?

@@ -75,10 +81,27 @@ public KeyVaultCertificates(long refreshInterval, KeyVaultClient keyVaultClient)
*/
public void updateKeyVaultClient(String keyVaultUri, String tenantId, String clientId, String clientSecret,
Copy link
Member

Choose a reason for hiding this comment

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

should we remove the old one?

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

Labels

azure-spring All azure-spring related issues azure-spring-jca

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

[FEATURE REQ] azure-security-keyvault-jca should support bearer tokens

3 participants