Skip to content

Conversation

@Ali-HENDA
Copy link
Contributor

@Ali-HENDA Ali-HENDA commented Nov 12, 2025

Q A
Branch? 7.4
Bug fix? yes
New feature? no
Deprecations? no
Issues Fix #62340
License MIT

This PR aligns the OIDC JWKS discovery cache with OpenID Connect best practices by making it dynamic and respecting provider cache headers.

Before

  • The JWKS was cached with a fixed lifetime, ignoring the OIDC provider’s cache policy.

After

  • The cache TTL is now automatically determined from the provider response:
    • Prefer Cache-Control: max-age
    • Fallback to Expires
    • When multiple providers are configured, the lowest TTL is applied.

@Ali-HENDA Ali-HENDA force-pushed the feature/oidc-auto-cache-expiry branch 2 times, most recently from 38cd272 to 981d813 Compare November 13, 2025 00:10
Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

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

I'd consider this as a bugfix for 7.4

@Ali-HENDA Ali-HENDA force-pushed the feature/oidc-auto-cache-expiry branch from 981d813 to cf49d44 Compare November 13, 2025 20:58
@nicolas-grekas nicolas-grekas force-pushed the feature/oidc-auto-cache-expiry branch from cf49d44 to 8898652 Compare November 14, 2025 09:55
@nicolas-grekas nicolas-grekas force-pushed the feature/oidc-auto-cache-expiry branch from 8898652 to 61acbf1 Compare November 14, 2025 09:57
@nicolas-grekas
Copy link
Member

Thank you @Ali-HENDA.

@nicolas-grekas nicolas-grekas merged commit 42a8072 into symfony:7.4 Nov 14, 2025
12 checks passed
This was referenced Nov 16, 2025
* The cache entry lifetime is automatically adjusted based on the lowest TTL
* advertised by the providers (via "Cache-Control: max-age" or "Expires" headers).
*
* @internal this method is public to enable async offline cache population
Copy link
Member

Choose a reason for hiding this comment

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

Where is this method called publicly ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because per PR #30572, async recomputation via Messenger only works with callables of the form [$service, 'publicMethod'], so the callback must be public.

}

$jwkSetResponses = [];
foreach ($client->stream($configResponses) as $response => $chunk) {
Copy link
Member

Choose a reason for hiding this comment

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

This is broken IMO:

  • $client might be undefined (if the loop is empty)
  • if the clients are different, there is no guarantee that calling stream will work. Responses must be streamed with the client that created them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After checking, this issue was already present before my patch. I didn't notice it when working on the cache handling. You're absolutely right to point it out.

Copy link
Member

Choose a reason for hiding this comment

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

@Ali-HENDA up to send a PR fixing this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, I’ll open a PR for this.

Comment on lines +348 to +351
$this->assertSame('user-cache-control', $handler->getUserBadgeFrom($token)->getUserIdentifier());
$this->assertSame(2, $requestCount);
$this->assertSame('user-cache-control', $handler->getUserBadgeFrom($token)->getUserIdentifier());
$this->assertSame(2, $requestCount);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are these lines duplicated?

And does this test actually test that the cache-control header is used as cache TTL?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The lines are duplicated because the first call fills the cache (2 requests) and the second call verifies that the cached JWKS is reused (request count stays at 2). The TTL is tested implicitly: since the second call happens
within the max-age window, it must be a cache hit.

Comment on lines +388 to +391
$this->assertSame('user-expires', $handler->getUserBadgeFrom($token)->getUserIdentifier());
$this->assertSame(2, $requestCount);
$this->assertSame('user-expires', $handler->getUserBadgeFrom($token)->getUserIdentifier());
$this->assertSame(2, $requestCount);
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same reason as above

nicolas-grekas added a commit that referenced this pull request Dec 5, 2025
…nt instances are used (Ali-HENDA)

This PR was merged into the 7.4 branch.

Discussion
----------

[Security][Http] Fix OIDC discovery when multiple HttpClient instances are used

| Q             | A
| ------------- | ---
| Branch?       | 7.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Issues        | Fix
| License       | MIT

This PR fixes an issue in the OIDC JWKS discovery logic revealed in the discussion of #62369.
$client->stream() was used incorrectly:
$client could be undefined, and responses must be streamed using the same client instance that created them, which breaks when multiple HttpClientInterface instances are configured.
The logic now performs sequential discovery per client, avoiding cross-client streaming and ensuring correctness.

This PR also hardens the "use" check ($key['use'] ?? null).

Commits
-------

7a885d2 [Security] Fix OIDC discovery when using multiple HttpClient instances
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OIDC Discovery - verification of key id/cache invalidation

5 participants