Skip to content

Conversation

@polatengin
Copy link
Contributor

@polatengin polatengin commented Dec 17, 2025

Fixes: #711

This PR adds caching to the authentication layer to improve performance and reduce unnecessary API calls.

Why it's needed:

The previous code created a new credential object every time the provider needed a token. This caused two problems:

For most credential types (client secret, certificate, managed identity, etc.): The Azure SDK caches tokens internally, but only within the same credential instance. By creating new credentials every time, we threw away the cache and forced the SDK to fetch a new token on each call.

For CLI-based credentials (Azure CLI and Azure Developer CLI): The Azure SDK does NOT cache tokens at all for these types. Every call to get a token runs the az or azd command, which is slow.

What this PR adds:

Credential object caching: We now reuse credential objects instead of creating new ones. This lets the Azure SDK's built-in token cache work properly.

Token caching for CLI credentials: Since CLI credentials don't have built-in caching, we added our own cache. Tokens are reused until they're within 5 minutes of expiring.

Result:

Fewer authentication requests to Azure AD
Faster operations when using CLI-based authentication
No external dependencies—all caching is in-memory

We also introduced a set of tests to improve code coverage;

go test -coverprofile=coverage.out -run "TestUnit" ./internal/api/... && go tool cover -func=coverage.out | grep -E "(auth\.go|total)"

Before:

github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:30:         Error                            0.0%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:56:         NewAuthBase                      100.0%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:62:         AuthenticateClientCertificate    0.0%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:90:         AuthenticateUsingCli             0.0%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:107:        AuthenticateUsingAzureDeveloperCli0.0%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:124:        AuthenticateClientSecret         0.0%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:146:        NewOidcCredential                28.6%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:180:        GetToken                         0.0%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:184:        AuthenticateOIDC                 38.5%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:218:        AuthenticateUserManagedIdentity  71.4%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:237:        AuthenticateSystemManagedIdentity71.4%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:255:        AuthenticateAzDOWorkloadIdentityFederation                        46.7%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:294:        createTokenRequestOptions        100.0%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:313:        getAssertion                     0.0%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:376:        GetTokenForScopes                57.1%
total:                                                                                  (statements)                     23.2%

After:

github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:31:         Error                                     100.0%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:79:         NewAuthBase                               100.0%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:86:         getOrCreateCredential                     100.0%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:115:        AuthenticateClientCertificate             63.6%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:146:        AuthenticateUsingCli                      87.5%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:165:        AuthenticateUsingAzureDeveloperCli        87.5%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:184:        AuthenticateClientSecret                  87.5%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:209:        NewOidcCredential                         92.9%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:243:        GetToken                                  0.0%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:247:        AuthenticateOIDC                          91.7%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:279:        AuthenticateUserManagedIdentity           100.0%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:300:        AuthenticateSystemManagedIdentity         100.0%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:320:        AuthenticateAzDOWorkloadIdentityFederation93.8%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:361:        createTokenRequestOptions                 100.0%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:380:        getAssertion                              94.1%
github.com/microsoft/terraform-provider-power-platform/internal/api/auth.go:443:        GetTokenForScopes                         100.0%
total:                                                                                  (statements)                              54.8%

@polatengin polatengin self-assigned this Dec 17, 2025
@polatengin polatengin requested a review from a team as a code owner December 17, 2025 18:58
Copilot AI review requested due to automatic review settings December 17, 2025 18:58
@polatengin polatengin added go Pull requests that update Go code security labels Dec 17, 2025
@polatengin polatengin linked an issue Dec 17, 2025 that may be closed by this pull request
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 implements a credential caching and retrieval mechanism to address the lack of credential reuse in the authentication layer. The changes ensure that Azure SDK credential objects are created once and reused across subsequent calls, enabling proper utilization of the SDK's built-in token caching and automatic renewal capabilities.

Key changes:

  • Introduces a credential holder pattern with thread-safe lazy initialization using sync.Once and sync.RWMutex
  • Refactors all eight authentication methods to use the new getOrCreateCredential helper
  • Adds comprehensive unit tests with concurrency validation, improving code coverage from 23.2% to 54.8%

Reviewed changes

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

File Description
internal/api/auth.go Adds credential caching infrastructure (credentialType enum, credentialHolder struct, credentials map with RWMutex) and refactors all authentication methods to use the new getOrCreateCredential helper for credential reuse
internal/api/auth_test.go Implements comprehensive unit tests covering credential caching behavior, thread safety with concurrent access, error handling, and authentication method functionality using mock credentials

polatengin and others added 2 commits December 22, 2025 07:45
if err != nil {
return "", time.Time{}, err
func (client *Auth) getOrCreateCredential(ctx context.Context, credType credentialType, factory func() (azcore.TokenCredential, error)) (azcore.TokenCredential, error) {
client.credentialsMutex.RLock()
Copy link
Contributor

Choose a reason for hiding this comment

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

what about token expiry? When do we invalidate the cache?

@mawasile mawasile added the run-acceptance-tests PR tag for triggering acceptance tests label Jan 21, 2026
@mawasile
Copy link
Contributor

@copilot fix linter issues

Copy link
Contributor

Copilot AI commented Jan 21, 2026

@mawasile I've opened a new pull request, #1047, to work on those changes. Once the pull request is ready, I'll request review from you.

* Initial plan

* fix: remove stray syntax errors in auth_test.go

Co-authored-by: mawasile <50197777+mawasile@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: mawasile <50197777+mawasile@users.noreply.github.com>
@codecov-commenter
Copy link

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
404 1 403 10
View the top 1 failed test(s) by shortest run time
github.com/microsoft/terraform-provider-power-platform/internal/api::[setup failed]
Stack Traces | 0s run time
Build error

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

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

Labels

go Pull requests that update Go code run-acceptance-tests PR tag for triggering acceptance tests security skip-changelog

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lack of Credential Reuse in GetTokenForScopes

4 participants